Skip to content

Fix phpstan/phpstan#14324: Foreach on constant array with closures reaching 32 entries causes crash#5246

Merged
staabm merged 3 commits intophpstan:2.1.xfrom
phpstan-bot:create-pull-request/patch-dfdlnal
Mar 19, 2026
Merged

Fix phpstan/phpstan#14324: Foreach on constant array with closures reaching 32 entries causes crash#5246
staabm merged 3 commits intophpstan:2.1.xfrom
phpstan-bot:create-pull-request/patch-dfdlnal

Conversation

@phpstan-bot
Copy link
Copy Markdown
Collaborator

Summary

Fixes a crash (internal error) when analysing a foreach over a constant array that contains 32 or more closure values. The crash was introduced in 2.1.41 and occurs because ConstantArrayType::getAllArrays() rebuilds the array using ConstantArrayTypeBuilder, which degrades to a general array when the closure count limit (32) is reached.

Changes

  • Added $builder->disableArrayDegradation() call in ConstantArrayType::getAllArrays() (src/Type/Constant/ConstantArrayType.php) to prevent the builder from degrading an already-existing constant array during reconstruction
  • Added regression test in tests/PHPStan/Analyser/nsrt/bug-14324.php

Root cause

ConstantArrayType::getAllArrays() reconstructs subsets of the array using ConstantArrayTypeBuilder. When the array contains 32+ closures, the builder's CLOSURES_COUNT_LIMIT triggers degradation to a general array type. The method then fails at the $array instanceof self assertion since the builder returned a non-constant array type. The fix disables array degradation in the builder since getAllArrays() is simply reconstructing subsets of an already-valid constant array.

Test

Added tests/PHPStan/Analyser/nsrt/bug-14324.php which reproduces the original crash scenario: a class with a static map of 29 closures that gets 3 more added in a foreach loop, breaching the 32-closure limit.

Fixes phpstan/phpstan#14324

…y has 32+ closures

- Disable array degradation in ConstantArrayType::getAllArrays() builder
- The builder was degrading to a general array due to CLOSURES_COUNT_LIMIT,
  causing a ShouldNotHappenException since getAllArrays() expects ConstantArrayType
- New regression test in tests/PHPStan/Analyser/nsrt/bug-14324.php
Comment thread tests/PHPStan/Analyser/data/bug-14324.php
phpstan-bot and others added 2 commits March 19, 2026 06:17
The original problem was an internal error/crash, so the regression test
belongs in AnalyserIntegrationTest rather than as an nsrt type inference test.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@@ -241,6 +241,7 @@ public function getAllArrays(): array
}

$builder = ConstantArrayTypeBuilder::createEmpty();
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we have similar code in the codebase which asserts the result of a getArray-method call on a ConstantArrayTypeBuilder object ?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both tests and static analysis pass.

The reviewer's question was informational — asking whether there are similar patterns elsewhere in the codebase. The answer is no: the getAllArrays() assertion at ConstantArrayType.php:250 is the only place that asserts getArray() returns a ConstantArrayType. No code changes are needed beyond what's already in the PR. There's nothing to commit or push.

Copy link
Copy Markdown
Contributor

@staabm staabm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the fix makes sense to me. ConstantArrayType->getAllArrays expects/assumes a array of ConstantArrayType will be returned.

therefore we cannot/should not degrade arrays in this path.

@staabm staabm requested a review from VincentLanglet March 19, 2026 06:42
@phpstan-bot
Copy link
Copy Markdown
Collaborator Author

The review from staabm is an approval with no requested code changes. They're confirming the fix is correct — ConstantArrayType->getAllArrays expects constant arrays, so disabling degradation in that path is the right approach.

Since this is a pure approval with no action items, there are no changes to make, commit, or push.

@staabm staabm self-assigned this Mar 19, 2026
@staabm staabm merged commit 873f1e6 into phpstan:2.1.x Mar 19, 2026
654 of 655 checks passed
@staabm staabm deleted the create-pull-request/patch-dfdlnal branch March 19, 2026 08:09
@phpstan-bot
Copy link
Copy Markdown
Collaborator Author

The review from VincentLanglet is an approval with no requested code changes. There's nothing to address — the PR is approved by both staabm and VincentLanglet.

phpstan-bot added a commit to phpstan-bot/phpstan-src that referenced this pull request Apr 7, 2026
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.

3 participants