Fix phpstan/phpstan#14265: Invalid "Offset might not exist on array"#5298
Open
phpstan-bot wants to merge 1 commit intophpstan:2.1.xfrom
Open
Fix phpstan/phpstan#14265: Invalid "Offset might not exist on array"#5298phpstan-bot wants to merge 1 commit intophpstan:2.1.xfrom
phpstan-bot wants to merge 1 commit intophpstan:2.1.xfrom
Conversation
- When array_keys($a) is passed as argument alongside a closure/arrow function, PHPStan now recognizes that $a[$key] is valid inside the callback - Extended the existing foreach(array_keys($a) as $key) special handling to also cover callbacks in function calls like array_reduce, array_map, etc. - New regression test in tests/PHPStan/Rules/Arrays/data/bug-14265.php Closes phpstan/phpstan#14265
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.
Summary
When using
array_keys($a)as input to a higher-order function likearray_reduce, accessing$a[$key]inside the callback was incorrectly reported as "Offset might not exist" for arrays with optional keys. The keys returned byarray_keys()are guaranteed to exist in the source array, so this was a false positive.Changes
detectArrayKeysInSiblingArgs()method insrc/Analyser/NodeScopeResolver.phpthat detects whenarray_keys($expr)appears as a sibling argument to a closure/arrow function in a function callapplyArrayKeysSourceToScope()method that injects type information for$expr[$param]into the callback scope, matching callback parameters whose type equals the source array's key typeprocessArgs()processArrowFunctionNode()andprocessClosureNode()tests/PHPStan/Rules/Arrays/data/bug-14265.phptestBug14265()inNonexistentOffsetInArrayDimFetchRuleTest.phpRoot cause
PHPStan already had special handling for
foreach (array_keys($a) as $key)that assigned the type of$a[$key]in the loop scope, recognizing that keys fromarray_keys()are always valid offsets. However, this handling didn't extend to callbacks passed to higher-order functions likearray_reduce(array_keys($a), fn($carry, $key) => $a[$key], ''). The type system lost the correlation between thearray_keys()result and the source array, so$a[$key]was checked independently, producing a false "might not exist" warning for optional keys.The fix extends the same approach: when a sibling argument in a function call is
array_keys($expr), the callback scope is enriched with the knowledge that$expr[$param]has a valid type, preventing the false positive.Test
Added a regression test reproducing the exact scenario from the issue: an array with an optional key (
k2?),array_keys()passed toarray_reduce, and the callback accessing the array with the key parameter. The test expects no errors.Fixes phpstan/phpstan#14265