Skip to content

Fix phpstan/phpstan#11533: Foreach to check the type of array is not taken into account#5272

Open
phpstan-bot wants to merge 1 commit intophpstan:2.1.xfrom
phpstan-bot:create-pull-request/patch-v1hmegu
Open

Fix phpstan/phpstan#11533: Foreach to check the type of array is not taken into account#5272
phpstan-bot wants to merge 1 commit intophpstan:2.1.xfrom
phpstan-bot:create-pull-request/patch-v1hmegu

Conversation

@phpstan-bot
Copy link
Collaborator

Summary

When iterating over a constant array of strings (e.g. ['need', 'field']) in a foreach loop and narrowing an array variable's offsets inside the body (via isset + is_string checks with throw), PHPStan did not propagate the per-element type narrowings to the variable after the loop. This caused false positive argument.type errors when passing the array to functions expecting specific key types.

Changes

  • Added post-foreach processing in src/Analyser/NodeScopeResolver.php that detects when a foreach iterates over a constant array of string literals and the body narrowed array dim-fetch expressions using the loop variable
  • For each defined array variable that was narrowed (not assigned) in the body, adds HasOffsetValueType accessories for each constant string value in the iterated array
  • Includes guards to avoid false positives:
    • Checks that the variable's type was not modified (assigned) in the body
    • Checks that the dim-fetch expression type was specifically tracked in the body scope (not just derived from the generic value type)
    • Checks that the narrowing is new (not already present before the foreach)

Root cause

When PHPStan processes a foreach body, the loop variable (e.g. $field) has a union type of all iterated values (e.g. 'need'|'field'). Type narrowing from conditions like is_string($param[$field]) creates expression types for $param[$field] but does not propagate HasOffsetValueType to $param because the dim type is a union (not a single ConstantStringType). After the loop, this narrowing information was lost.

The fix adds a post-foreach processing step that recognizes when a constant string array was iterated and the loop body narrowed dim-fetch expressions using the loop variable, then applies per-element HasOffsetValueType accessories to restore the narrowing information.

Test

Added regression test in tests/PHPStan/Analyser/nsrt/bug-11533.php covering:

  • Basic foreach with isset + is_string narrowing and throw (the reported issue)
  • Variant using array_key_exists instead of isset

Fixes phpstan/phpstan#11533

- After foreach over constant string arrays like ['need', 'field'], propagate per-element type narrowings (HasOffsetValueType) to variables narrowed inside the loop body
- Added logic in NodeScopeResolver post-foreach processing to detect variables whose dim-fetch expressions were narrowed (e.g. via isset + is_string) and apply HasOffsetValueType for each constant array element
- Guards against false positives by checking the variable wasn't modified (assigned) in the body and that the dim-fetch narrowing is new (not pre-existing)
- New regression test in tests/PHPStan/Analyser/nsrt/bug-11533.php
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