Fix phpstan/phpstan#14274: "Variable might not be defined" false positive#5216
Merged
ondrejmirtes merged 3 commits intophpstan:2.1.xfrom Mar 13, 2026
Merged
Conversation
…tive - Fixed invalidateExpression() dropping all ConditionalExpressionHolders for a variable when only some holders had an invalidated condition guard - Previously, `continue 3` skipped the entire variable's holders when any single holder's condition guard matched the invalidated expression - Now filters holders individually, preserving valid holders (e.g. those guarded by $has_staged_update) when unrelated holders (e.g. those guarded by $messages) are invalidated - New regression test in tests/PHPStan/Rules/Variables/data/bug-14274.php
staabm
reviewed
Mar 13, 2026
Contributor
staabm
left a comment
There was a problem hiding this comment.
needs a regression test for phpstan/phpstan#12373
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Collaborator
Author
|
The background |
staabm
approved these changes
Mar 13, 2026
Collaborator
Author
|
The review from staabm is APPROVED — no further changes are requested. Looking at the PR diff and recent commits, the regression test for phpstan/phpstan#12373 that was previously requested has already been added:
The recent commits confirm this:
Everything is already in order — no additional changes needed. |
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
Fixes a false positive "Variable might not be defined" error when maybe-defined variables are guarded by a boolean flag inside complex boolean expressions (
||combined with&&). The issue occurred when multipleifblocks used the same guarded variables, and an unrelated variable assignment in anifbody caused the conditional expression holders to be incorrectly dropped.Changes
MutatingScope::invalidateExpression()insrc/Analyser/MutatingScope.phpto filterConditionalExpressionHolderinstances individually rather than dropping all holders for a variable when any single holder has an invalidated condition guardtests/PHPStan/Rules/Variables/data/bug-14274.phpand corresponding test method inDefinedVariableRuleTest.phpRoot cause
When
invalidateExpression()was called (e.g., when assigning to$messages[]), the code usedcontinue 3to skip the entire set ofConditionalExpressionHolderinstances for a variable if any holder had a condition guard matching the invalidated expression. This meant that ifcreateConditionalExpressions()had added a spurious holder guarded by$messages(as a type guard) alongside the original holder guarded by$has_staged_update, invalidating$messageswould also discard the$has_staged_update-guarded holder. This caused subsequentifblocks to lose the information that the variable was definitely defined when$has_staged_updatewas true.The fix changes the logic to filter holders individually: only holders whose condition guards match the invalidated expression are removed, while other holders for the same variable are preserved.
Test
The regression test reproduces the exact scenario from the issue: an if/else block that sets a boolean flag and defines variables via list assignment, followed by multiple
ifblocks using||with&&-guarded access to those variables. Without the fix, the thirdifblock incorrectly reports "Variable might not be defined" for variables that are properly guarded by the boolean flag.Fixes phpstan/phpstan#14274