Skip to content

Do not make php-parser and phpdoc-parser properties public when inlining getters in the phar build - #6410

Merged
ondrejmirtes merged 1 commit into
2.2.xfrom
inliner-no-vendor-publicize
Sep 10, 2026
Merged

Do not make php-parser and phpdoc-parser properties public when inlining getters in the phar build#6410
ondrejmirtes merged 1 commit into
2.2.xfrom
inliner-no-vendor-publicize

Conversation

@ondrejmirtes

@ondrejmirtes ondrejmirtes commented Sep 10, 2026

Copy link
Copy Markdown
Member

Follow-up to #6406. The phar build's getter inliner made properties of the three vendor packages public (stamped with #[PrivateProperty] / #[ProtectedProperty]) so that their single-return getters could be inlined. For php-parser and phpdoc-parser that is unsafe: the phar ships both under their own, unprefixed namespaces (PhpParser, PHPStan\PhpDocParser are in scoper's exclude-namespaces), and projects install them on their own too, so the copy loaded at run time may be one whose properties are still non-public. Their properties are no longer touched. better-reflection is PHPStan's own fork and keeps being inlined.

What changed

  • InlineCallCollector skips a call site whenever the inlined body would need a property declared under vendor/nikic/php-parser or vendor/phpstan/phpdoc-parser made public (PROTECTED_PACKAGE_DIRECTORIES). The check runs against every publicize target (declaring class, trait file, subclass redeclarations). Getters of the two packages that only read public properties or call public methods are still inlined, and call sites inside them are still rewritten.
  • InlineEditsApplier refuses such a target with an exception instead of applying it, so a collector regression fails the build loudly. The protected directories are a constructor argument defaulting to the same two, covered by a new test.

Before vs. after

Collector output replayed with the applier's outermost-wins logic, then confirmed by a full compiler/bin/prepare run in a copy of the tree.

before after
inlined call sites 9,005 8,426
of which inside vendor files 813 562
files rewritten 1,039 976
properties made public 851 823
of which in better-reflection 73 73
of which in php-parser + phpdoc-parser 28 0
attribute stamps under php-parser + phpdoc-parser after prepare 28 0

The 587 dropped sites are exactly the ones that needed a php-parser (407) or phpdoc-parser (180) property; nothing else is lost. 336 of them were calls from src/ into those getters, 251 were calls inside the two packages. Eight nested src/ edits previously shadowed by an outer edit now apply on their own. Largest individual losses: NodeAbstract::getStartLine (203 sites), NodeAbstract::getAttributes (104), TokenIterator::currentTokenValue (53), Comment::getText (49), TokenIterator::currentTokenLine (46), TokenIterator::currentTokenIndex (34). No src/ getter reads a property inherited from a php-parser parent, so no PHPStan-declared callee is affected.

The level-0 collection analysis reports the same findings before and after; the compiler test suite, its level-8 analysis and phpcs pass. The CPU cost of the dropped sites was not benchmarked; at the 28–40 ns/frame figure from #6406 it is well under half a percent.

🤖 Generated with Claude Code

https://claude.ai/code/session_01MenQLNmxZKVgpFuzRRTBGW

…ing getters in the phar build

The phar ships both packages under their own, unprefixed namespaces, and
projects install them on their own too, so the copy loaded at run time may
be one whose properties are still non-public. The collector skips a call
site whenever the inlined body would need such a property made public, and
the applier refuses such a target instead of stamping it. better-reflection
is PHPStan's own fork and keeps being inlined; call sites inside the two
packages and their getters reading public members are still inlined.

Inlined call sites 9,005 -> 8,426, properties made public 851 -> 823 (the
28 php-parser and phpdoc-parser ones gone), rewritten files 1,039 -> 976.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MenQLNmxZKVgpFuzRRTBGW
@ondrejmirtes ondrejmirtes changed the title Do not make vendor properties public when inlining getters in the phar build Do not make php-parser and phpdoc-parser properties public when inlining getters in the phar build Sep 10, 2026
@ondrejmirtes
ondrejmirtes force-pushed the inliner-no-vendor-publicize branch from 5a17d2b to 0710158 Compare September 10, 2026 12:36
@ondrejmirtes
ondrejmirtes merged commit ce1c164 into 2.2.x Sep 10, 2026
772 of 805 checks passed
@ondrejmirtes
ondrejmirtes deleted the inliner-no-vendor-publicize branch September 10, 2026 13:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant