Wire RichParser node visitors via DI factory instead of private property hack - #8215
Merged
Merged
Conversation
…rty hack Replace PHPStanContainerMemento reflection with a RichParserFactory service, registered in config/phpstan/parser.neon. The factory builds RichParser with a DirectExtensionsCollection of the two visitors Rector needs, so no private property of PHPStan internals is touched. A plain "nodeVisitors" argument in the config is not enough: PHPStan's AutowiredExtensionsExtension::beforeCompile() overwrites that argument for every service definition that instantiates the class directly. Factory-created definitions are skipped, so the explicit visitor list survives.
TomasVotruba
force-pushed
the
remove-privates-accessor-rich-parser
branch
from
July 28, 2026 13:10
c0f210e to
070ca62
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follow-up to #8208 — same goal, no
PrivatesAccessoron PHPStan internals.Before
PHPStanContainerMemento::removeRichVisitors()read the privateRichParser::$nodeVisitorsproperty, filtered it, and wrote a new collection back. Every PHPStan internal change breaks it (that is what #8208 had to repair, and the 2.2.6 crash before it).After
A small factory service builds the parser through the public constructor, and the config picks the visitors:
PHPStanContainerMementois deleted.Why a factory, and not just a
nodeVisitors:argumentA plain argument in the config is silently dropped.
PHPStan\DependencyInjection\AutowiredExtensionsExtension::beforeCompile()walks all definitions and overwrites every#[AutowiredExtensions]parameter with the lazy container-backed collection — but it skips definitions whose creator is not the class itself, i.e. factory-created ones.Do we still need the filtering at all?
Checked: with all 23 visitors enabled the whole test suite passes and
bin/rector process --dry-runover this repo produces identical output — the #9492 node-replacement bug is fixed upstream. The filter is still worth keeping for speed, running all visitors on every parsed file costs roughly 10% more CPU on a full run of this repo (~510s -> ~550-600s user time, 30s -> 37s wall).Regression test for #9492 (
PHPStanPrinterTest) stays, now without the manual visitor-removal call, since the container wiring does it.