Changeset 63462
- Timestamp:
- 09/04/2026 06:23:52 AM (less than one hour ago)
- Location:
- trunk/tests/phpstan
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/tests/phpstan/README.md
r63460 r63462 212 212 The results cache alone is not the problem. PHPStan invalidates that itself when the configuration changes, and [`HookDocsResultCacheMetaExtension`](HookDocsResultCacheMetaExtension.php) already folds every file in this directory into its key, so it is discarded when one of them is edited. What survives either is the per-file reflection, which is keyed by the source file's own contents and has no way to know that reading it now yields something else. CI keys its cache on these files for the same reason; see [`.github/workflows/reusable-phpstan-static-analysis-v1.yml`](../../.github/workflows/reusable-phpstan-static-analysis-v1.yml). 213 213 214 The same cache is worth clearing after analysing a subset of the tree. A file named on the command line is analysed, but a file merely *read* on its behalf is parsed without these extensions, and the reflection stored for it carries no derived shape. A later full run reads that back and reports against a type that is no longer what the docblock says, which is the same silence as above arriving from the other direction.214 Analyzing a subset of the tree used to call for the same treatment, the same silence arriving from the other direction. A file named on the command line is analyzed, but a file merely *read* on its behalf went to PHPStan's simple parser, where these visitors do not run, so the reflection stored for it carried no derived shape — wrong for that run, and there in the cache for the next full run to restore. [`base.neon`](base.neon) now has the simple parser wrap the rich one, so every parse rewrites the same docblocks and a run over a subset derives what a full run derives. It does so by redefining one of PHPStan's own parser services, which is not a documented extension point; if a hash notation type ever looks wrong after a PHPStan upgrade, check that definition first. 215 215 216 216 Baseline generation is exempt from that last hazard. [`generate-baselines.php`](generate-baselines.php) points its analysis at `.cache/baselines` instead, a directory only it writes to and only ever from a full run, so a baseline can never record a message derived from reflection some earlier narrowed run left behind. Clearing the cache after editing anything in this directory still applies to it, and the `rm -rf .cache` above covers both. -
trunk/tests/phpstan/base.neon
r63451 r63462 62 62 tags: 63 63 - phpstan.resultCacheMetaExtension 64 65 # Runs the visitors above over every file PHPStan parses, not only the ones it 66 # analyzes. 67 # 68 # `phpstan.parser.richParserNodeVisitor` is honored by PHPStan's RichParser, and 69 # PathRoutingParser sends a file there only when it is one of the files being 70 # analyzed. Everything else — a file merely read so that a function or class it 71 # declares can be reflected — goes to the simple parser, which applies only the 72 # name resolver. 73 # 74 # PHPStan can do that because its own two parsers agree about everything 75 # reflection exposes: the simple one is wrapped in a CleaningParser, whose 76 # CleaningVisitor empties function, method and closure bodies and touches nothing 77 # else. Docblocks and signatures come out of either parser identically, so what is 78 # reflected out of a file does not depend on whether that file was analyzed, and 79 # the per-file reflection cache can be keyed on the file's contents alone. 80 # 81 # HashNotationVisitor breaks that agreement. It rewrites `@param`, `@return` and 82 # `@var` docblocks, which are exactly what reflection exposes, so a file read 83 # through the simple parser reflects the documented `array` where the same file 84 # analyzed reflects the shape its hash notation describes. Analyzing a subset of 85 # the tree then reports against types no longer derived, and writes that reading 86 # into the shared cache for the next full run to restore. 87 # 88 # Wrapping the rich parser rather than the plain one restores the agreement: every 89 # parse rewrites the same docblocks, the cleaning still happens on top, and the 90 # reflection cache is keyed on contents correctly again. 91 # 92 # `currentPhpVersionSimpleParser` and `currentPhpVersionRichParser` are PHPStan's 93 # own service names, from its conf/parsers.neon, and are not a documented extension 94 # point. Should a future release rename either, this definition stops being wired 95 # into anything and the behavior above returns; the errors it prevents are all of 96 # the quiet sort, so check this first when a hash notation type looks wrong. 97 # 98 # `arguments!` replaces the inherited arguments rather than merging with them. 99 # Without the `!`, the original `wrappedParser` argument survives and the container 100 # fails to build with "Unknown named parameter $wrappedParser". 101 currentPhpVersionSimpleParser: 102 class: PHPStan\Parser\CleaningParser 103 arguments!: 104 wrappedParser: @currentPhpVersionRichParser 105 autowired: false 64 106 65 107 parameters:
Note:
See TracChangeset
for help on using the changeset viewer.
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)