├── .editorconfig
├── .gitignore
├── LICENSE.md
├── README.md
├── basic
├── 1.php
└── README.md
├── beginner
├── 1.php
├── 2.php
├── 3.php
├── 4.php
└── README.md
├── composer.json
├── composer.lock
├── phpstan.dist.neon
└── pictures
├── highlighting-comments.png
└── splited-screen.png
/.editorconfig:
--------------------------------------------------------------------------------
1 | # EditorConfig is awesome: http://EditorConfig.org
2 |
3 | # top-most EditorConfig file
4 | root = true
5 |
6 | # Unix-style newlines with a newline ending every file
7 | [*]
8 | end_of_line = lf
9 | insert_final_newline = true
10 | charset = utf-8
11 |
12 | # PHP - http://php.net/
13 | [*.php]
14 | indent_style = tab
15 | indent_size = 4
16 |
17 | # NEON - https://ne-on.org/
18 | [{*.neon,*.neon.dist}]
19 | indent_style = tab
20 | indent_size = 4
21 |
22 | # CommonMark - https://commonmark.org/
23 | # GitHub Flavored Markdown Spec - https://github.github.com/gfm/
24 | [*.md]
25 | trim_trailing_whitespace = false
26 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /cache/
2 | /resultCache.php
3 | /vendor/*
4 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | # GNU Free Documentation License
2 |
3 | Version 1.3, 3 November 2008
4 |
5 | Copyright (C) 2000, 2001, 2002, 2007, 2008 Free Software Foundation,
6 | Inc.
7 |
8 | Everyone is permitted to copy and distribute verbatim copies of this
9 | license document, but changing it is not allowed.
10 |
11 | ## 0. PREAMBLE
12 |
13 | The purpose of this License is to make a manual, textbook, or other
14 | functional and useful document "free" in the sense of freedom: to
15 | assure everyone the effective freedom to copy and redistribute it,
16 | with or without modifying it, either commercially or noncommercially.
17 | Secondarily, this License preserves for the author and publisher a way
18 | to get credit for their work, while not being considered responsible
19 | for modifications made by others.
20 |
21 | This License is a kind of "copyleft", which means that derivative
22 | works of the document must themselves be free in the same sense. It
23 | complements the GNU General Public License, which is a copyleft
24 | license designed for free software.
25 |
26 | We have designed this License in order to use it for manuals for free
27 | software, because free software needs free documentation: a free
28 | program should come with manuals providing the same freedoms that the
29 | software does. But this License is not limited to software manuals; it
30 | can be used for any textual work, regardless of subject matter or
31 | whether it is published as a printed book. We recommend this License
32 | principally for works whose purpose is instruction or reference.
33 |
34 | ## 1. APPLICABILITY AND DEFINITIONS
35 |
36 | This License applies to any manual or other work, in any medium, that
37 | contains a notice placed by the copyright holder saying it can be
38 | distributed under the terms of this License. Such a notice grants a
39 | world-wide, royalty-free license, unlimited in duration, to use that
40 | work under the conditions stated herein. The "Document", below, refers
41 | to any such manual or work. Any member of the public is a licensee,
42 | and is addressed as "you". You accept the license if you copy, modify
43 | or distribute the work in a way requiring permission under copyright
44 | law.
45 |
46 | A "Modified Version" of the Document means any work containing the
47 | Document or a portion of it, either copied verbatim, or with
48 | modifications and/or translated into another language.
49 |
50 | A "Secondary Section" is a named appendix or a front-matter section of
51 | the Document that deals exclusively with the relationship of the
52 | publishers or authors of the Document to the Document's overall
53 | subject (or to related matters) and contains nothing that could fall
54 | directly within that overall subject. (Thus, if the Document is in
55 | part a textbook of mathematics, a Secondary Section may not explain
56 | any mathematics.) The relationship could be a matter of historical
57 | connection with the subject or with related matters, or of legal,
58 | commercial, philosophical, ethical or political position regarding
59 | them.
60 |
61 | The "Invariant Sections" are certain Secondary Sections whose titles
62 | are designated, as being those of Invariant Sections, in the notice
63 | that says that the Document is released under this License. If a
64 | section does not fit the above definition of Secondary then it is not
65 | allowed to be designated as Invariant. The Document may contain zero
66 | Invariant Sections. If the Document does not identify any Invariant
67 | Sections then there are none.
68 |
69 | The "Cover Texts" are certain short passages of text that are listed,
70 | as Front-Cover Texts or Back-Cover Texts, in the notice that says that
71 | the Document is released under this License. A Front-Cover Text may be
72 | at most 5 words, and a Back-Cover Text may be at most 25 words.
73 |
74 | A "Transparent" copy of the Document means a machine-readable copy,
75 | represented in a format whose specification is available to the
76 | general public, that is suitable for revising the document
77 | straightforwardly with generic text editors or (for images composed of
78 | pixels) generic paint programs or (for drawings) some widely available
79 | drawing editor, and that is suitable for input to text formatters or
80 | for automatic translation to a variety of formats suitable for input
81 | to text formatters. A copy made in an otherwise Transparent file
82 | format whose markup, or absence of markup, has been arranged to thwart
83 | or discourage subsequent modification by readers is not Transparent.
84 | An image format is not Transparent if used for any substantial amount
85 | of text. A copy that is not "Transparent" is called "Opaque".
86 |
87 | Examples of suitable formats for Transparent copies include plain
88 | ASCII without markup, Texinfo input format, LaTeX input format, SGML
89 | or XML using a publicly available DTD, and standard-conforming simple
90 | HTML, PostScript or PDF designed for human modification. Examples of
91 | transparent image formats include PNG, XCF and JPG. Opaque formats
92 | include proprietary formats that can be read and edited only by
93 | proprietary word processors, SGML or XML for which the DTD and/or
94 | processing tools are not generally available, and the
95 | machine-generated HTML, PostScript or PDF produced by some word
96 | processors for output purposes only.
97 |
98 | The "Title Page" means, for a printed book, the title page itself,
99 | plus such following pages as are needed to hold, legibly, the material
100 | this License requires to appear in the title page. For works in
101 | formats which do not have any title page as such, "Title Page" means
102 | the text near the most prominent appearance of the work's title,
103 | preceding the beginning of the body of the text.
104 |
105 | The "publisher" means any person or entity that distributes copies of
106 | the Document to the public.
107 |
108 | A section "Entitled XYZ" means a named subunit of the Document whose
109 | title either is precisely XYZ or contains XYZ in parentheses following
110 | text that translates XYZ in another language. (Here XYZ stands for a
111 | specific section name mentioned below, such as "Acknowledgements",
112 | "Dedications", "Endorsements", or "History".) To "Preserve the Title"
113 | of such a section when you modify the Document means that it remains a
114 | section "Entitled XYZ" according to this definition.
115 |
116 | The Document may include Warranty Disclaimers next to the notice which
117 | states that this License applies to the Document. These Warranty
118 | Disclaimers are considered to be included by reference in this
119 | License, but only as regards disclaiming warranties: any other
120 | implication that these Warranty Disclaimers may have is void and has
121 | no effect on the meaning of this License.
122 |
123 | ## 2. VERBATIM COPYING
124 |
125 | You may copy and distribute the Document in any medium, either
126 | commercially or noncommercially, provided that this License, the
127 | copyright notices, and the license notice saying this License applies
128 | to the Document are reproduced in all copies, and that you add no
129 | other conditions whatsoever to those of this License. You may not use
130 | technical measures to obstruct or control the reading or further
131 | copying of the copies you make or distribute. However, you may accept
132 | compensation in exchange for copies. If you distribute a large enough
133 | number of copies you must also follow the conditions in section 3.
134 |
135 | You may also lend copies, under the same conditions stated above, and
136 | you may publicly display copies.
137 |
138 | ## 3. COPYING IN QUANTITY
139 |
140 | If you publish printed copies (or copies in media that commonly have
141 | printed covers) of the Document, numbering more than 100, and the
142 | Document's license notice requires Cover Texts, you must enclose the
143 | copies in covers that carry, clearly and legibly, all these Cover
144 | Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on
145 | the back cover. Both covers must also clearly and legibly identify you
146 | as the publisher of these copies. The front cover must present the
147 | full title with all words of the title equally prominent and visible.
148 | You may add other material on the covers in addition. Copying with
149 | changes limited to the covers, as long as they preserve the title of
150 | the Document and satisfy these conditions, can be treated as verbatim
151 | copying in other respects.
152 |
153 | If the required texts for either cover are too voluminous to fit
154 | legibly, you should put the first ones listed (as many as fit
155 | reasonably) on the actual cover, and continue the rest onto adjacent
156 | pages.
157 |
158 | If you publish or distribute Opaque copies of the Document numbering
159 | more than 100, you must either include a machine-readable Transparent
160 | copy along with each Opaque copy, or state in or with each Opaque copy
161 | a computer-network location from which the general network-using
162 | public has access to download using public-standard network protocols
163 | a complete Transparent copy of the Document, free of added material.
164 | If you use the latter option, you must take reasonably prudent steps,
165 | when you begin distribution of Opaque copies in quantity, to ensure
166 | that this Transparent copy will remain thus accessible at the stated
167 | location until at least one year after the last time you distribute an
168 | Opaque copy (directly or through your agents or retailers) of that
169 | edition to the public.
170 |
171 | It is requested, but not required, that you contact the authors of the
172 | Document well before redistributing any large number of copies, to
173 | give them a chance to provide you with an updated version of the
174 | Document.
175 |
176 | ## 4. MODIFICATIONS
177 |
178 | You may copy and distribute a Modified Version of the Document under
179 | the conditions of sections 2 and 3 above, provided that you release
180 | the Modified Version under precisely this License, with the Modified
181 | Version filling the role of the Document, thus licensing distribution
182 | and modification of the Modified Version to whoever possesses a copy
183 | of it. In addition, you must do these things in the Modified Version:
184 |
185 | - A. Use in the Title Page (and on the covers, if any) a title
186 | distinct from that of the Document, and from those of previous
187 | versions (which should, if there were any, be listed in the
188 | History section of the Document). You may use the same title as a
189 | previous version if the original publisher of that version
190 | gives permission.
191 | - B. List on the Title Page, as authors, one or more persons or
192 | entities responsible for authorship of the modifications in the
193 | Modified Version, together with at least five of the principal
194 | authors of the Document (all of its principal authors, if it has
195 | fewer than five), unless they release you from this requirement.
196 | - C. State on the Title page the name of the publisher of the
197 | Modified Version, as the publisher.
198 | - D. Preserve all the copyright notices of the Document.
199 | - E. Add an appropriate copyright notice for your modifications
200 | adjacent to the other copyright notices.
201 | - F. Include, immediately after the copyright notices, a license
202 | notice giving the public permission to use the Modified Version
203 | under the terms of this License, in the form shown in the
204 | Addendum below.
205 | - G. Preserve in that license notice the full lists of Invariant
206 | Sections and required Cover Texts given in the Document's
207 | license notice.
208 | - H. Include an unaltered copy of this License.
209 | - I. Preserve the section Entitled "History", Preserve its Title,
210 | and add to it an item stating at least the title, year, new
211 | authors, and publisher of the Modified Version as given on the
212 | Title Page. If there is no section Entitled "History" in the
213 | Document, create one stating the title, year, authors, and
214 | publisher of the Document as given on its Title Page, then add an
215 | item describing the Modified Version as stated in the
216 | previous sentence.
217 | - J. Preserve the network location, if any, given in the Document
218 | for public access to a Transparent copy of the Document, and
219 | likewise the network locations given in the Document for previous
220 | versions it was based on. These may be placed in the "History"
221 | section. You may omit a network location for a work that was
222 | published at least four years before the Document itself, or if
223 | the original publisher of the version it refers to
224 | gives permission.
225 | - K. For any section Entitled "Acknowledgements" or "Dedications",
226 | Preserve the Title of the section, and preserve in the section all
227 | the substance and tone of each of the contributor acknowledgements
228 | and/or dedications given therein.
229 | - L. Preserve all the Invariant Sections of the Document, unaltered
230 | in their text and in their titles. Section numbers or the
231 | equivalent are not considered part of the section titles.
232 | - M. Delete any section Entitled "Endorsements". Such a section may
233 | not be included in the Modified Version.
234 | - N. Do not retitle any existing section to be Entitled
235 | "Endorsements" or to conflict in title with any Invariant Section.
236 | - O. Preserve any Warranty Disclaimers.
237 |
238 | If the Modified Version includes new front-matter sections or
239 | appendices that qualify as Secondary Sections and contain no material
240 | copied from the Document, you may at your option designate some or all
241 | of these sections as invariant. To do this, add their titles to the
242 | list of Invariant Sections in the Modified Version's license notice.
243 | These titles must be distinct from any other section titles.
244 |
245 | You may add a section Entitled "Endorsements", provided it contains
246 | nothing but endorsements of your Modified Version by various
247 | parties—for example, statements of peer review or that the text has
248 | been approved by an organization as the authoritative definition of a
249 | standard.
250 |
251 | You may add a passage of up to five words as a Front-Cover Text, and a
252 | passage of up to 25 words as a Back-Cover Text, to the end of the list
253 | of Cover Texts in the Modified Version. Only one passage of
254 | Front-Cover Text and one of Back-Cover Text may be added by (or
255 | through arrangements made by) any one entity. If the Document already
256 | includes a cover text for the same cover, previously added by you or
257 | by arrangement made by the same entity you are acting on behalf of,
258 | you may not add another; but you may replace the old one, on explicit
259 | permission from the previous publisher that added the old one.
260 |
261 | The author(s) and publisher(s) of the Document do not by this License
262 | give permission to use their names for publicity for or to assert or
263 | imply endorsement of any Modified Version.
264 |
265 | ## 5. COMBINING DOCUMENTS
266 |
267 | You may combine the Document with other documents released under this
268 | License, under the terms defined in section 4 above for modified
269 | versions, provided that you include in the combination all of the
270 | Invariant Sections of all of the original documents, unmodified, and
271 | list them all as Invariant Sections of your combined work in its
272 | license notice, and that you preserve all their Warranty Disclaimers.
273 |
274 | The combined work need only contain one copy of this License, and
275 | multiple identical Invariant Sections may be replaced with a single
276 | copy. If there are multiple Invariant Sections with the same name but
277 | different contents, make the title of each such section unique by
278 | adding at the end of it, in parentheses, the name of the original
279 | author or publisher of that section if known, or else a unique number.
280 | Make the same adjustment to the section titles in the list of
281 | Invariant Sections in the license notice of the combined work.
282 |
283 | In the combination, you must combine any sections Entitled "History"
284 | in the various original documents, forming one section Entitled
285 | "History"; likewise combine any sections Entitled "Acknowledgements",
286 | and any sections Entitled "Dedications". You must delete all sections
287 | Entitled "Endorsements".
288 |
289 | ## 6. COLLECTIONS OF DOCUMENTS
290 |
291 | You may make a collection consisting of the Document and other
292 | documents released under this License, and replace the individual
293 | copies of this License in the various documents with a single copy
294 | that is included in the collection, provided that you follow the rules
295 | of this License for verbatim copying of each of the documents in all
296 | other respects.
297 |
298 | You may extract a single document from such a collection, and
299 | distribute it individually under this License, provided you insert a
300 | copy of this License into the extracted document, and follow this
301 | License in all other respects regarding verbatim copying of that
302 | document.
303 |
304 | ## 7. AGGREGATION WITH INDEPENDENT WORKS
305 |
306 | A compilation of the Document or its derivatives with other separate
307 | and independent documents or works, in or on a volume of a storage or
308 | distribution medium, is called an "aggregate" if the copyright
309 | resulting from the compilation is not used to limit the legal rights
310 | of the compilation's users beyond what the individual works permit.
311 | When the Document is included in an aggregate, this License does not
312 | apply to the other works in the aggregate which are not themselves
313 | derivative works of the Document.
314 |
315 | If the Cover Text requirement of section 3 is applicable to these
316 | copies of the Document, then if the Document is less than one half of
317 | the entire aggregate, the Document's Cover Texts may be placed on
318 | covers that bracket the Document within the aggregate, or the
319 | electronic equivalent of covers if the Document is in electronic form.
320 | Otherwise they must appear on printed covers that bracket the whole
321 | aggregate.
322 |
323 | ## 8. TRANSLATION
324 |
325 | Translation is considered a kind of modification, so you may
326 | distribute translations of the Document under the terms of section 4.
327 | Replacing Invariant Sections with translations requires special
328 | permission from their copyright holders, but you may include
329 | translations of some or all Invariant Sections in addition to the
330 | original versions of these Invariant Sections. You may include a
331 | translation of this License, and all the license notices in the
332 | Document, and any Warranty Disclaimers, provided that you also include
333 | the original English version of this License and the original versions
334 | of those notices and disclaimers. In case of a disagreement between
335 | the translation and the original version of this License or a notice
336 | or disclaimer, the original version will prevail.
337 |
338 | If a section in the Document is Entitled "Acknowledgements",
339 | "Dedications", or "History", the requirement (section 4) to Preserve
340 | its Title (section 1) will typically require changing the actual
341 | title.
342 |
343 | ## 9. TERMINATION
344 |
345 | You may not copy, modify, sublicense, or distribute the Document
346 | except as expressly provided under this License. Any attempt otherwise
347 | to copy, modify, sublicense, or distribute it is void, and will
348 | automatically terminate your rights under this License.
349 |
350 | However, if you cease all violation of this License, then your license
351 | from a particular copyright holder is reinstated (a) provisionally,
352 | unless and until the copyright holder explicitly and finally
353 | terminates your license, and (b) permanently, if the copyright holder
354 | fails to notify you of the violation by some reasonable means prior to
355 | 60 days after the cessation.
356 |
357 | Moreover, your license from a particular copyright holder is
358 | reinstated permanently if the copyright holder notifies you of the
359 | violation by some reasonable means, this is the first time you have
360 | received notice of violation of this License (for any work) from that
361 | copyright holder, and you cure the violation prior to 30 days after
362 | your receipt of the notice.
363 |
364 | Termination of your rights under this section does not terminate the
365 | licenses of parties who have received copies or rights from you under
366 | this License. If your rights have been terminated and not permanently
367 | reinstated, receipt of a copy of some or all of the same material does
368 | not give you any rights to use it.
369 |
370 | ## 10. FUTURE REVISIONS OF THIS LICENSE
371 |
372 | The Free Software Foundation may publish new, revised versions of the
373 | GNU Free Documentation License from time to time. Such new versions
374 | will be similar in spirit to the present version, but may differ in
375 | detail to address new problems or concerns. See
376 | .
377 |
378 | Each version of the License is given a distinguishing version number.
379 | If the Document specifies that a particular numbered version of this
380 | License "or any later version" applies to it, you have the option of
381 | following the terms and conditions either of that specified version or
382 | of any later version that has been published (not as a draft) by the
383 | Free Software Foundation. If the Document does not specify a version
384 | number of this License, you may choose any version ever published (not
385 | as a draft) by the Free Software Foundation. If the Document specifies
386 | that a proxy can decide which future versions of this License can be
387 | used, that proxy's public statement of acceptance of a version
388 | permanently authorizes you to choose that version for the Document.
389 |
390 | ## 11. RELICENSING
391 |
392 | "Massive Multiauthor Collaboration Site" (or "MMC Site") means any
393 | World Wide Web server that publishes copyrightable works and also
394 | provides prominent facilities for anybody to edit those works. A
395 | public wiki that anybody can edit is an example of such a server. A
396 | "Massive Multiauthor Collaboration" (or "MMC") contained in the site
397 | means any set of copyrightable works thus published on the MMC site.
398 |
399 | "CC-BY-SA" means the Creative Commons Attribution-Share Alike 3.0
400 | license published by Creative Commons Corporation, a not-for-profit
401 | corporation with a principal place of business in San Francisco,
402 | California, as well as future copyleft versions of that license
403 | published by that same organization.
404 |
405 | "Incorporate" means to publish or republish a Document, in whole or in
406 | part, as part of another Document.
407 |
408 | An MMC is "eligible for relicensing" if it is licensed under this
409 | License, and if all works that were first published under this License
410 | somewhere other than this MMC, and subsequently incorporated in whole
411 | or in part into the MMC, (1) had no cover texts or invariant sections,
412 | and (2) were thus incorporated prior to November 1, 2008.
413 |
414 | The operator of an MMC Site may republish an MMC contained in the site
415 | under CC-BY-SA on the same site at any time before August 1, 2009,
416 | provided the MMC is eligible for relicensing.
417 |
418 | ## ADDENDUM: How to use this License for your documents
419 |
420 | To use this License in a document you have written, include a copy of
421 | the License in the document and put the following copyright and
422 | license notices just after the title page:
423 |
424 | Copyright (C) YEAR YOUR NAME.
425 | Permission is granted to copy, distribute and/or modify this document
426 | under the terms of the GNU Free Documentation License, Version 1.3
427 | or any later version published by the Free Software Foundation;
428 | with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
429 | A copy of the license is included in the section entitled "GNU
430 | Free Documentation License".
431 |
432 | If you have Invariant Sections, Front-Cover Texts and Back-Cover
433 | Texts, replace the "with … Texts." line with this:
434 |
435 | with the Invariant Sections being LIST THEIR TITLES, with the
436 | Front-Cover Texts being LIST, and with the Back-Cover Texts being LIST.
437 |
438 | If you have Invariant Sections without Cover Texts, or some other
439 | combination of the three, merge those two alternatives to suit the
440 | situation.
441 |
442 | If your document contains nontrivial examples of program code, we
443 | recommend releasing these examples in parallel under your choice of
444 | free software license, such as the GNU General Public License, to
445 | permit their use in free software.
446 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # PHPStan型付けチュートリアル
2 |
3 | PHPStanを使った型付けをWebブラウザ上で体験できるチュートリアルです。
4 |
5 | コード編集中にリアルタイムでPHPStanのフィードバックを得て「**PHPStanとペアプログラミングをする**」感覚を獲得してください。
6 |
7 | ## チュートリアル
8 |
9 | 1. 🌱 [**PHPStan型付けチュートリアル 入門編**](beginner/README.md)
10 | 2. 🔰 [**PHPStan型付けチュートリアル 基礎編**](basic/README.md) ***(工事中)***
11 |
12 | ## 取り組み方
13 |
14 | チュートリアルには節見出しごとに、以下のようなブロックがあります。
15 |
16 | > [!NOTE]
17 | > この節のコードは以下で確認できます
18 | > * **PHPStan Playground**: `https://phpstan.org/...`
19 | > * **File**: `xxx.php`
20 | > * **CLI**: `./vendor/bin/phpstan analyze beginner/xxx.php`
21 |
22 | ### 🖥️ Webブラウザで取り組む
23 |
24 | チュートリアル本文にある **PHPStan Playground**: `https://phpstan.org/...` のリンクからWeb上のPlaygroundにアクセスできます。
25 |
26 | Webブラウザのウィンドウを分割し、記事本文とPHPStan Playgroundを並べて表示すると便利です。
27 |
28 | 
29 |
30 | ### ローカルで実行する
31 |
32 | このGitリポジトリをローカルに `git clone` してください。
33 |
34 | > [!TIP]
35 | > PHP 8.0以降と[Composer]がインストールされている必要があります。
36 | > `git clone` 後にディレクトリ内に移動し `composer install` を実行してください。
37 |
38 | #### 📜 エディタ上から実行する
39 |
40 | チュートリアルを読み進めながら、同じディレクトリがあるファイルを編集してください。
41 |
42 | > [!TIP]
43 | > エディタ画面で編集中にPHPStanの出力を表示できるようにすることを **強く推奨** します。
44 | > **PhpStorm**、**VS Code**、**GNU Emacs**、**Vim**などでは拡張を有効化することで実現できます。
45 |
46 | > [!WARNING]
47 | > エディタ内からリアルタイムでPHPStanを実行する環境が用意できない場合は**Webブラウザを使ってください**。
48 |
49 | [Composer]: https://getcomposer.org/
50 |
51 | #### **非推奨** 🚫 ターミナルから実行する
52 |
53 | このチュートリアルは、エディタ画面から透過的にPHPStanを実行することが理想です。
54 |
55 | どうしても実行できない場合は端末から**CLI**で指定されている`./vendor/bin/phpstan analyze beginner/xxx.php`のようなコマンドを実行してください。
56 |
57 | ## Copyright
58 |
59 | この文書は[GNU自由文書ライセンス]により自由に利用できます。
60 |
61 | Copyright (c) 2025 USAMI Kenta
62 | Permission is granted to copy, distribute and/or modify this document
63 | under the terms of the GNU Free Documentation License, Version 1.3
64 | or any later version published by the Free Software Foundation;
65 | with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
66 | A copy of the license is included in the section entitled "GNU
67 | Free Documentation License".
68 |
69 | コード部分については[BSD Zero Clause License]とします。
70 |
71 | BSD Zero Clause License
72 |
73 | Copyright (c) 2025 USAMI Kenta
74 |
75 | Permission to use, copy, modify, and/or distribute this software for any
76 | purpose with or without fee is hereby granted.
77 |
78 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
79 | REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
80 | AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
81 | INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
82 | LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
83 | OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
84 | PERFORMANCE OF THIS SOFTWARE.
85 |
86 | [GNU自由文書ライセンス]: https://www.gnu.org/licenses/fdl-1.3.html
87 | [gfdl-ja]: https://doclicenses.opensource.jp/GFDL-1.2/GFDL-1.2.html
88 | [BSD Zero Clause License]: https://choosealicense.com/licenses/0bsd/
89 |
--------------------------------------------------------------------------------
/basic/1.php:
--------------------------------------------------------------------------------
1 | $id,
9 | 'Name' => $name,
10 | 'BirthDay' => new DateTimeImmutable($birthday),
11 | ];
12 |
13 | return $result;
14 | }
15 |
16 | public function fetchUsers(): array
17 | {
18 | // 仮実装なので仮データを返す
19 | $users = [];
20 | $users[] = $this->buildUser(1, 'Miku', '2007-08-31');
21 | $users[] = $this->buildUser(2, 'Rin', '2007-12-27');
22 | $users[] = $this->buildUser(3, 'Len', '2007-12-27');
23 | $users[] = $this->buildUser(4, 'Luka', '2009-01-30');
24 |
25 | return $users;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/basic/README.md:
--------------------------------------------------------------------------------
1 | # PHPStan型付けチュートリアル 基礎編
2 |
3 |
4 | ## 1. 関数の戻り値に型をつけよう
5 |
6 | 既存の関数には適切な戻り値をつけることが大切ですが、型を付けるのに必要以上に手間をかけるのは徒労です。
7 |
8 | このコースでは極力手間をかけずに型を書くことを身につけましょう。
9 |
10 | > [!NOTE]
11 | > この節のコードは以下で確認できます
12 | > * **PHPStan Playground**:
13 | > * **File**: [`1.php`](./1.php)
14 | > * **CLI**: `./vendor/bin/phpstan analyze basic/1.php`
15 |
16 | ``` php
17 | $id,
25 | 'Name' => $name,
26 | 'BirthDay' => new DateTimeImmutable($birthday),
27 | ];
28 |
29 | return $result;
30 | }
31 |
32 | public function fetchUsers(): array
33 | {
34 | // 仮実装なので仮データを返す
35 | $users = [];
36 | $users[] = $this->buildUser(1, 'Miku', '2007-08-31');
37 | $users[] = $this->buildUser(2, 'Rin', '2007-12-27');
38 | $users[] = $this->buildUser(3, 'Len', '2007-12-27');
39 | $users[] = $this->buildUser(4, 'Luka', '2009-01-30');
40 |
41 | return $users;
42 | }
43 | }
44 | ```
45 |
46 | 初期状態ではPHPStanは以下のようなエラーを発生させます。
47 |
48 | > [!WARNING]
49 | >
50 | > ```
51 | > Method UsersBuilder::buildUser() return type has no value type specified in iterable type array.
52 | > Method UsersBuilder::fetchUsers() return type has no value type specified in iterable type array.
53 | > ```
54 | > **See**: [Solving PHPStan error "No value type specified in iterable type"](https://phpstan.org/blog/solving-phpstan-no-value-type-specified-in-iterable-type)
55 |
56 | PHPStanは基本的に `array` だけの型宣言には厳しい対応をします。なぜなら、`array`を一皮剥いたら何が返ってくるかわからない、つまりは**型なし**だからです。そのため、配列の内部構造も公開仕様として語ってあげなければいけません。
57 |
58 | PHPDocで配列に詳細な型を記述する方法は大きく分けて二つあります:
59 |
60 | * `array`, `array` (ジェネリック配列記法)
61 | * 同じ構造が繰り返す場合に使う
62 | * `array{}`, `array{key: value}`, `array{int, string, string}` (array-shapes記法)
63 | * 配列の中のキーごとに別の意味の値が格納される場合に使う
64 |
65 | 使い慣れてくればどちらがどちらか混乱することはないのですが大変初心者殺しであることは間違いありません。
66 |
67 | そこで使えるのが `\PHPStan\dumpPhpDocType()` です。これは `\PHPStan\dumpType()` と似ていますが、PHPDocでそのまま使える記法で出力してくれる機能です。
68 |
69 | 手始めに `buildUser()` メソッドに型をつけてみましょう。
70 |
71 | ```php
72 | public function buildUser(int $id, string $name, string $birthday): array
73 | {
74 | $result = [
75 | 'ID' => $id,
76 | 'Name' => $name,
77 | 'BirthDay' => new DateTimeImmutable($birthday),
78 | ];
79 | \PHPStan\dumpPhpDocType($result);
80 | # Dumped type: array{ID: int, Name: string, BirthDay: DateTimeImmutable}
81 |
82 | return $result;
83 | }
84 | ```
85 |
86 | 型が出力されました。これをコピペしてPHPDocに貼り付けます。
87 |
88 | ```php
89 | /**
90 | * @return array{ID: int, Name: string, BirthDay: DateTimeImmutable}
91 | */
92 | ```
93 |
94 | 今度は同じように `fetchUsers()` に型をつけてみましょう。
95 |
96 | うまく行っていれば、こういう型が出力されるはずです。
97 |
98 | ```
99 | Dumped type: array{array{ID: int, Name: string, BirthDay: DateTimeImmutable}, array{ID: int, Name: string, BirthDay: DateTimeImmutable}, array{ID: int, Name: string, BirthDay: DateTimeImmutable}, array{ID: int, Name: string, BirthDay: DateTimeImmutable}}
100 | ```
101 |
102 | なんだか長い型が出てしまいましたね… これはPHPStanが賢すぎて、`$users`がきちんと長さ4の配列だと認識してくれてしまっているからこその問題です。
103 |
104 | 整形すると以下のようになります。
105 |
106 | ```php
107 | /**
108 | * @return array{
109 | * 0: array{ID: int, Name: string, BirthDay: DateTimeImmutable},
110 | * 1: array{ID: int, Name: string, BirthDay: DateTimeImmutable},
111 | * 2: array{ID: int, Name: string, BirthDay: DateTimeImmutable},
112 | * 3: array{ID: int, Name: string, BirthDay: DateTimeImmutable},
113 | * }
114 | */
115 | ```
116 |
117 | これをコピペしてまたPHPDocに貼り付ける… でもいいのですが、コードにはこういうことが書いてあります
118 |
119 | ``` php
120 | // 仮実装なので仮データを返す
121 | ```
122 |
123 | ということは、本実装では何個になるかというのは、あまり具体的な意味はなさそうです。
124 |
125 | さきほどのPHPDoc記法の使い分けを再掲しましょう。
126 |
127 | > * `array`, `array` (ジェネリック配列記法)
128 | > * **同じ構造が繰り返す場合に使う**
129 | > * `array{}`, `array{key: value}`, `array{int, string, string}` (array-shapes記法)
130 | > * 配列の中のキーごとに別の意味の値が格納される場合に使う
131 |
132 | 今回の場合はどの要素も引数は違いますが、同じ大きく見れば同じ構造のものの繰り返しと考えられます。
133 |
134 | つまり、このように書けます。
135 |
136 | ```php
137 | /**
138 | * @return array
139 | */
140 | ```
141 | この型は読みやすいように改行しても構いません。
142 |
143 | ```php
144 | /**
145 | * @return array
150 | */
151 | ```
152 |
--------------------------------------------------------------------------------
/beginner/1.php:
--------------------------------------------------------------------------------
1 | $authors
16 | */
17 | public function __construct(
18 | public string $title,
19 | public array $authors,
20 | ) {}
21 | }
22 |
23 | /**
24 | * @param non-empty-string $word
25 | * @param 'asc'|'desc' $order
26 | * @param positive-int $page
27 | * @return list
28 | */
29 | function search(string $word, string $order, int $page): array
30 | {
31 | // 本来は検索エンジンからデータを取得する
32 | return match ($page) {
33 | 1 => [new Book('', [])],
34 | default => [],
35 | };
36 | }
37 |
38 | $word = filter_var($_GET['word'] ?? '');
39 | $order = filter_var($_GET['order'] ?? 'asc');
40 | $page = filter_var($_GET['page'] ?? 1, FILTER_VALIDATE_INT);
41 |
42 | \PHPStan\dumpType(compact('word', 'order', 'page'));
43 |
44 | $books = search($word, $order, $page);
45 |
46 | \PHPStan\dumpType(compact('books'));
47 |
--------------------------------------------------------------------------------
/beginner/4.php:
--------------------------------------------------------------------------------
1 | [!NOTE]
14 | > この節のコードは以下で確認できます
15 | > * **PHPStan Playground**:
16 | > * **File**: [`1.php`](./1.php)
17 | > * **CLI**: `./vendor/bin/phpstan analyze beginner/1.php`
18 |
19 | ```php
20 | $a = 'foo';
21 | $b = 'bar';
22 | $c = $a . $b;
23 | // . は文字列を結合する演算子
24 |
25 | \PHPStan\dumpType($a);
26 | \PHPStan\dumpType($b);
27 | \PHPStan\dumpType($c);
28 | ```
29 |
30 | 複数の値をまとめてチェックしたいときは[`compact()`]で配列にまとめることでわかりやすくなることもあります。
31 |
32 | ```php
33 | $n = 5;
34 | $m = 2;
35 | $l = $n / $m;
36 | \PHPStan\dumpType(compact('n', 'm', 'l'));
37 | ```
38 |
39 | 「これってPHPを実行した結果を画面に表示してるだけじゃないの?」と思われるかもしれません。禅問答のようですが、「***そうであって、そうではない***」のです。
40 |
41 | 何を言っているかわからないと思うので、次のようなコードを考えてみましょう。
42 |
43 | ```php
44 | $n = 5;
45 | if (rand() === 1) {
46 | $m = 2;
47 | } else {
48 | $m = 5;
49 | }
50 |
51 | $l = $n / $m;
52 | \PHPStan\dumpType(compact('n', 'm', 'l'));
53 | ```
54 |
55 | `rand() === 1` という条件が成り立つ確率は大雑把に「**21億分の1**」です。PHPStanは`rand() === 1`という確率的な処理は**行なっていません**。どちらでも僅かにでも可能性があるならば、PHPStanは**どちらの可能性もある**と判断して`2|5`という型をつけます。さらに`$l = $n / $m`という式はどうでしょうか。`$n`には`5`という型がついていますが、`$m`は`2`と`5`の可能性があるので、`$l = 5 / 2` (= `2.5`) と `$l = 5 / 5` (= `1`) という2パターンが考えられます。ここでPHPStanは`$l`に`1|2.5`という型をつけます。これはPHPStanが行なう型付けの特殊な例などではなく、***PHPStanが常に行なっていること***です。
56 |
57 | > [!CAUTION]
58 | > `\PHPStan\dumpType()` は静的解析時に用いられる擬似的な関数ですが、実行時に定義されません。
59 | >
60 | > 実アプリケーションでは実行する前、あるいはユニットテスト実行前に取り除いてください。
61 |
62 | > [!TIP]
63 | > * PHPのコードは文末に`;`が必要です
64 | > * `.`演算子は文字列として結合します (`+`は常に数値の加算および配列マージを意味します)
65 | > * * `/` 演算子は数値の除算(割り算)を行います
66 |
67 | > [!IMPORTANT]
68 | > 🔜 **コードを好きに書き換えてみて、納得できたら次に進んでください**
69 |
70 | ## 2. 型宣言で関数に型をつける
71 |
72 | > [!NOTE]
73 | > この節のコードは以下で確認できます
74 | > * **PHPStan Playground**:
75 | > * **File**: [`2.php`](./2.php)
76 | > * **CLI**: `./vendor/bin/phpstan analyze beginner/2.php`
77 |
78 | PHPの関数に型を付けてみましょう。
79 |
80 | ```php
81 | function label($title)
82 | {
83 | return "label:{$title}";
84 | }
85 |
86 | \PHPStan\Testing\assertType('string', label('foo'));
87 | ```
88 |
89 | > [!TIP]
90 | > `\PHPStan\Testing\assertType(expected, actual)` は値が期待する型とPHPStanが認識している型の **文字列表現の一致** をチェックする関数です。`expected`と`actual`が同じ文字列なら何も出力されなくなります。
91 | >
92 | > ここでは使っていませんが、部分型関係を用いてチェックする `\PHPStan\Testing\assertSuperType(expected, actual)`もあります。
93 |
94 | > [!TIP]
95 | > 型宣言を含まない関数 `function f($arg1, $arg2) { ... }` は、どんな型の引数も受け入れ、どんな型の値を返すこともできます。
96 | >
97 | > * `function f(int $arg1, float $arg2) { ... }`
98 | > * `()`内に`type $arg`と書くことで、パラメータの型を宣言します
99 | > * `function f($arg1, $arg2): int|float { ... }`
100 | > * `()` の次に `: type` と書くことで、戻り値の型を宣言します
101 | >
102 | > パラメータと戻り値の型宣言は組み合わせることができます。
103 |
104 | PHPではパラメータ(仮引数リスト)や戻り値に型宣言を追加できます。関数やメソッドで型宣言された型は、実行時に**必ず保証**されます。
105 |
106 | 保証されるということは次のことを意味します:
107 |
108 | * パラメータで宣言された型は、実装内で必ず制約を満たします
109 | * ⇒ **制約を満たさない値が渡されることを心配する必要はありません**
110 | * 呼び出した結果、必ず宣言された型の制約を満たす戻り値が返されます
111 | * ⇒ **制約を満たさない値が返されることを心配する必要はありません**
112 |
113 | それぞれの箇所では、型宣言されたものが静的型付きであることが必ず保証されます。
114 |
115 | > [!TIP]
116 | > PHPの型宣言についてどのように振る舞うかチェックできます
117 | > * [php-playで確認する](https://php-play.dev/?c=DwfgDgFmAEAmCmBjANgQwE7wBQGcAu6AlongPp4CeY8OAvAIwCUA3AFCsBmArgHYmEB7HtDQAjeMlwFCPAObQAJHkJ5k8RgC5o%2BInNYBvVgEhMeLumEAiMRI36lKtQF9LbJ%2BwBuGUrC4BbMCwbSQByDgEBEMYWVi90H39A4KwmGKA&v=8.4&f=console)
118 |
119 | > [!IMPORTANT]
120 | > 🔜 **型を追加してエラーが出なくなったら次に進んでください**
121 |
122 | ## 3. 型を絞り込む
123 |
124 | > [!NOTE]
125 | > この節のコードは以下で確認できます
126 | > * **PHPStan Playground**:
127 | > * **File**: [`3.php`](./3.php)
128 | > * **CLI**: `./vendor/bin/phpstan analyze beginner/3.php`
129 |
130 | ユーザーがフォームから検索して、結果の書籍一覧を表示する画面を考えてみましょう。
131 |
132 | `search()`関数の実装は次のようになっています。
133 |
134 | ```php
135 | /**
136 | * @param non-empty-string $word
137 | * @param 'asc'|'desc' $order
138 | * @param positive-int $page
139 | * @return list
140 | */
141 | function search(string $word, string $order, int $page): array
142 | {
143 | // 本来は検索エンジンからデータを取得する
144 | return match ($page) {
145 | 1 => [new Book('', [])],
146 | default => [],
147 | };
148 | }
149 | ```
150 |
151 | `/** … */`は**Doc comment**といい、関数やクラスの説明を記述できます。 `@param`や`@return`のような記述は**PHPDocタグ**と呼びます。`@param`はパラメータの詳細な型を、`@return`は関数・メソッドの戻り値の型を記述します。
152 |
153 | * `@param non-empty-string $word`
154 | * 空文字列での検索は不正なので、関数呼び出し側の責任でチェックする
155 | * `non-empty-string`とは、`''`(空文字列)以外の文字列のことです
156 | * `@param 'asc'|'desc' $order`
157 | * 検索結果を昇順と降順のどちらに並び変えるか
158 | * `@param positive-int $page`
159 | * 検索のページ数:最小値は`1`
160 | * `@return list`
161 | * `Book`クラスのリスト
162 | * [`list`型について](https://scrapbox.io/php/list%E5%9E%8B)
163 |
164 | > [!WARNING]
165 | > Doc commentは、必ず `/** ... */` (`*`が二つ!)から始まります。
166 | > 範囲コメントの `/* ... */` とは区別されるので十分に気をつけてください。
167 | >
168 | > エディタによってはPHPDocタグが色付けされるかによって区別できます。
169 | > 
170 |
171 | 続いて、外部からの入力を値として取得します。
172 |
173 | ```php
174 | $word = filter_var($_GET['word'] ?? '');
175 | $order = filter_var($_GET['order'] ?? 'asc');
176 | $page = filter_var($_GET['page'] ?? 1, FILTER_VALIDATE_INT);
177 |
178 | $books = search($word, $order, $page);
179 | // 初期状態では以下のエラーが発生する
180 | // Parameter #1 $word of function search expects non-empty-string, string|false given.
181 | // Parameter #2 $order of function search expects 'asc'|'desc', string|false given.
182 | // Parameter #3 $page of function search expects int<1, max>, int|false given.
183 | ```
184 |
185 | > [!TIP]
186 | > * [`filter_var()`](https://www.php.net/filter_var)
187 | > * 値をフィルタリングする関数です (名前に反して変数以外もフィルタできます)
188 | > * PHPStanは[検証フィルタ]とオプションによって型が変わります
189 |
190 | PHPStanは比較により**型を絞り込む**(type narrowing)ことができます。
191 | コードに以下のようなコードを追加して型を確認してみてください。
192 |
193 | ```php
194 | $word = filter_var($_GET['word'] ?? '');
195 | \PHPStan\dumpType($word); // DumpedType: string|false
196 |
197 | if ($word === '' || $word === false) {
198 | \PHPStan\dumpType($word); // DumpedType: ''|false
199 | } else {
200 | \PHPStan\dumpType($word); // DumpedType: non-empty-string
201 | }
202 |
203 | \PHPStan\dumpType($word); // DumpedType: string|false
204 | ```
205 |
206 | PHPStanは**制御フロー解析**を実装しており、`if`や`foreach`といった制御構造に従った変数スコープを保持しています。上記のコードでは初期状態で`string|false`だった変数が`if`と`else`でそれぞれ`''|false`と`non-empty-string`に分岐し、合流後は`string|false`に**戻っている**ことが確認できます。
207 |
208 | 型が絞り込まれた状態で制御フローを中断することで、その型を絞り込めます。中断とは、`return` `throw` `continue` `break` `exit` あるいは `never` 型の関数を読み込むなどです。
209 |
210 | ```php
211 | $word = filter_var($_GET['word'] ?? '');
212 | \PHPStan\dumpType($word); // DumpedType: string|false
213 |
214 | if ($word === '' || $word === false) {
215 | throw new RangeException('$word を入力してください');
216 | } else {
217 | \PHPStan\dumpType($word); // DumpedType: non-empty-string
218 | }
219 |
220 | \PHPStan\dumpType($word); // DumpedType: non-empty-string
221 | ```
222 |
223 | これで型が絞り込まれた`else`の状態で固定できました。`else`のコードはまるごと削除しても構いません。さらに、型の絞り込みは**式の内部**でも起こります。
224 |
225 | ```php
226 | // strlen() に false を渡してしまう可能性があるのでエラー
227 | if (strlen($word) === 0 || $word === false) {
228 | // Parameter #1 $string of function strlen expects string, string|false given.
229 | throw new RangeException('$word を入力してください');
230 | }
231 | ```
232 |
233 | これは `||` の右辺と左辺を入れ替えることで解決します。
234 |
235 | ```php
236 | // false のときに左辺で処理が打ち切られるので strlen() の呼び出しを防げる
237 | if ($word === false || strlen($word) === 0) {
238 | ```
239 |
240 | もっとも、このパターンは[`in_array()`](https://www.php.net/in_array)関数を用いて簡潔に絞り込めます。
241 |
242 | ```php
243 | if (in_array($word, [false, ''], true)) {
244 | throw new RangeException('$word を入力してください');
245 | }
246 | ```
247 |
248 | このように`in_array($var, ['foo', 'bar', 'buz'], true)`と書くことで、`$var === 'foo' || $var === 'bar' || $var === 'buz'`と等価になり、PHPStanも型の絞り込みを適切に認識します。
249 |
250 | 同じように、ほかの変数`$order`と`$page`の型も絞り込んでみてください。
251 |
252 | > [!IMPORTANT]
253 | > 🔜 **実装を修正してエラーが出なくなったら次に進んでください**
254 | > * `search()`を呼び出す際に渡す値の型を適切に絞り込みます
255 | > * `search()`の実装内部でエラーが出ないように適当な値を埋めてください
256 |
257 | ## 4. 型宣言で安全に型をつける
258 |
259 | 一方で、**ファイル単位**で `declare(strict_types=1);` の有無によって、スカラー型について「関数(メソッド)を呼び出す際の引数(argument, 実引数)」および「関数(メソッド)が返す戻り値の型」の振る舞いが変わります。
260 |
261 | * `strict_types=1`**あり**
262 | * 値と型が一致しないと`TypeError`を送出します
263 | * `strict_types=1`**なし** (または`0`)
264 | * [**関数のコンテクスト**][関数のコンテクスト]における型の相互変換を行い、文脈に沿わない値に`TypeError`を発生します
265 |
266 | 以下のようなコードを考えてみましょう。
267 |
268 | > [!NOTE]
269 | > この節のコードは以下で確認できます
270 | > * **PHPStan Playground**:
271 | > * **File**: [`4.php`](./4.php)
272 | > * **CLI**: `./vendor/bin/phpstan analyze beginner/4.php`
273 |
274 | ```php
275 | [!TIP]
330 | > 今回はとても大雑把に型をつけていますが、「数値文字列」ではなく「整数を表す文字列」だけをサポートしたい場合などはPHPStan 2.1時点ではPHPDocだけでは判定できず、PHPStan拡張を実装する必要があります。
331 | > この章ではこのような使い方ができるということだけを認識できれば目的達成です。
332 |
333 | > [!IMPORTANT]
334 | > 🔜 **実装と型宣言を修正してエラーが出なくなれば、この章は修了です🎉**
335 |
336 | ## 入門編の修了
337 |
338 | 🎉 修了おめでとうございます!
339 |
340 | ここまで学んだことを整理しましょう。
341 |
342 | * `\PHPStan\dumpType()`でPHPStanが認識している型を確認できる
343 | * `\PHPStan\Testing\assertType()`で期待する型との比較もできる
344 | * PHPの基本機能で関数・メソッドに型を付けることができる
345 | * PHPStanは制御フロー解析により型を絞り込める
346 | * PHPでは実行できるがPHPStanが受け付けないコードも存在することを認識できる
347 | * PHPDocタグでより詳細な型を付けることができる
348 | * `declare(strict_types=1)`の有無での振る舞いの差異がわかる
349 | * `filter_var()`を使った型の検査方法がわかる
350 | * 条件付き戻り値型の存在を認識している
351 |
352 | ここまでできれば、細かい理窟は抜きにして「PHPStanを使える」と言って差し支えないと思います。
353 |
354 | もちろん全ての機能を直ちに使いこなせるようになっている必要はありません。とはいえ、コードを書いて期待通りの型がついていない原因をチェックできるようになったといえるでしょう。
355 |
356 | より詳細なPHPStanの使い方を身に付けるために次のステップに進みましょう!
357 |
358 | [関数のコンテクスト]: https://www.php.net/manual/ja/language.types.type-juggling.php#language.types.type-juggling.function
359 | [`compact()`]: https://www.php.net/compact
360 | [検証フィルタ]: https://www.php.net/manual/ja/filter.filters.validate.php
361 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "zonuexe/phpstan-typing-tutorial",
3 | "description": "Tutorial on typing with PHPStan",
4 | "license": "0BSD",
5 | "type": "project",
6 | "require-dev": {
7 | "phpstan/phpstan": "^2.1"
8 | },
9 | "config": {
10 | "sort-packages": true
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/composer.lock:
--------------------------------------------------------------------------------
1 | {
2 | "_readme": [
3 | "This file locks the dependencies of your project to a known state",
4 | "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
5 | "This file is @generated automatically"
6 | ],
7 | "content-hash": "7205af82ff0e8536ae7da4d72555a379",
8 | "packages": [],
9 | "packages-dev": [
10 | {
11 | "name": "phpstan/phpstan",
12 | "version": "2.1.17",
13 | "source": {
14 | "type": "git",
15 | "url": "https://github.com/phpstan/phpstan.git",
16 | "reference": "89b5ef665716fa2a52ecd2633f21007a6a349053"
17 | },
18 | "dist": {
19 | "type": "zip",
20 | "url": "https://api.github.com/repos/phpstan/phpstan/zipball/89b5ef665716fa2a52ecd2633f21007a6a349053",
21 | "reference": "89b5ef665716fa2a52ecd2633f21007a6a349053",
22 | "shasum": ""
23 | },
24 | "require": {
25 | "php": "^7.4|^8.0"
26 | },
27 | "conflict": {
28 | "phpstan/phpstan-shim": "*"
29 | },
30 | "bin": [
31 | "phpstan",
32 | "phpstan.phar"
33 | ],
34 | "type": "library",
35 | "autoload": {
36 | "files": [
37 | "bootstrap.php"
38 | ]
39 | },
40 | "notification-url": "https://packagist.org/downloads/",
41 | "license": [
42 | "MIT"
43 | ],
44 | "description": "PHPStan - PHP Static Analysis Tool",
45 | "keywords": [
46 | "dev",
47 | "static analysis"
48 | ],
49 | "support": {
50 | "docs": "https://phpstan.org/user-guide/getting-started",
51 | "forum": "https://github.com/phpstan/phpstan/discussions",
52 | "issues": "https://github.com/phpstan/phpstan/issues",
53 | "security": "https://github.com/phpstan/phpstan/security/policy",
54 | "source": "https://github.com/phpstan/phpstan-src"
55 | },
56 | "funding": [
57 | {
58 | "url": "https://github.com/ondrejmirtes",
59 | "type": "github"
60 | },
61 | {
62 | "url": "https://github.com/phpstan",
63 | "type": "github"
64 | }
65 | ],
66 | "time": "2025-05-21T20:55:28+00:00"
67 | }
68 | ],
69 | "aliases": [],
70 | "minimum-stability": "stable",
71 | "stability-flags": {},
72 | "prefer-stable": false,
73 | "prefer-lowest": false,
74 | "platform": {},
75 | "platform-dev": {},
76 | "plugin-api-version": "2.6.0"
77 | }
78 |
--------------------------------------------------------------------------------
/phpstan.dist.neon:
--------------------------------------------------------------------------------
1 | parameters:
2 | level: max
3 | phpVersion: 80401
4 | paths:
5 | - beginner/
6 | - basic/
7 | tmpDir: .
8 | includes:
9 | - vendor/phpstan/phpstan/conf/bleedingEdge.neon
10 |
--------------------------------------------------------------------------------
/pictures/highlighting-comments.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zonuexe/phpstan-typing-tutorial/dcb5b5f538f896129026c13de3a74e020bfd693f/pictures/highlighting-comments.png
--------------------------------------------------------------------------------
/pictures/splited-screen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zonuexe/phpstan-typing-tutorial/dcb5b5f538f896129026c13de3a74e020bfd693f/pictures/splited-screen.png
--------------------------------------------------------------------------------