Resolve constant offsets on constant arrays through the key index - #6442
Merged
Conversation
ConstantArrayType::isSuperTypeOf() asks the other array about every key with hasOffsetValueType() and getOffsetValueType(), and both scanned the whole key list with isSuperTypeOf() per key, so comparing two array shapes was quadratic in their size. The scope's conditional-expression matching compares the shape of a variable against every recorded condition on it, which made a method with dozens of `$params['key'] ?? null` reads over a large optional array shape spend seconds in ConstantStringType::isSuperTypeOf. Constant integer and string offsets now resolve through the existing value-keyed index: a hit is verified with isSuperTypeOf() before it is used, a miss keeps the full scan, and isOptionalKey() reads a set instead of in_array() over the optional keys. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GvDxWpzXzticTTm5eLCsb2
Collaborator
|
You've opened the pull request against the latest branch 2.3.x. PHPStan 2.3 is not going to be released for months. If your code is relevant on 2.2.x and you want it to be released sooner, please rebase your pull request and change its target to 2.2.x. |
Contributor
@ondrejmirtes should we have a phpbench script for this case? |
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.
Problem
ConstantArrayType::isSuperTypeOf()asks the other array about every key withhasOffsetValueType()andgetOffsetValueType(), and both scanned the whole key list withisSuperTypeOf()per key, so comparing two array shapes was quadratic in their size.Since 29c49f2 / 77527df every
$params['key'] ?? nullre-specifies$params, and the scope's conditional-expression matching compares the shape against every recorded condition on it. A method with 85 such reads over an 85-key optional array shape (Slevomat'sGeneratePremiseTextsAiExcellenceResult::create()) spent ~10 s inConstantStringType::isSuperTypeOf(119M calls in a single-file SPX profile) and was the whole measurable 2.3.x slowdown on that project.Change
Constant integer/string offsets now resolve through the existing value-keyed
getKeyIndexMap()inrecursiveHasOffsetValueType()andgetOffsetValueType(): a hit is verified withisSuperTypeOf()before it is used, a miss keeps the full scan (which also covers the unsealed extras), andisOptionalKey()reads a set instead ofin_array()over the optional keys.Verification
tests/PHPStan/Type,tests/PHPStan/Analyser,tests/PHPStan/Rulesgreen; phpcs and self-analysis clean.🤖 Generated with Claude Code
https://claude.ai/code/session_01GvDxWpzXzticTTm5eLCsb2