Fix phpstan/phpstan#12597: 'Variable might not be undefined' in if-statement after in_array check.#5384
Open
phpstan-bot wants to merge 2 commits intophpstan:2.1.xfrom
Open
Conversation
…ay check - Added subtype matching for conditional expressions in MutatingScope::processSpecifiedTypes - After exact-match conditional resolution, a second pass checks if specified types are subtypes of guard types for maybe-defined variables - Limited to Variable targets with Maybe certainty to avoid interfering with type narrowing - New regression test in tests/PHPStan/Rules/Variables/data/bug-12597.php
Contributor
VincentLanglet
left a comment
There was a problem hiding this comment.
Add non regression test
class HelloWorld
{
public function test(mixed $type): void
{
if (is_int($type) || is_string($type)) {
$message = 'Hello!';
}
if (is_int($type)) {
$this->message($message);
}
}
public function message(string $message): void {}
}
class Foo {}
class Bar {}
class HelloWorld2
{
public function test(mixed $type): void
{
if (is_int($type) || is_object($type)) {
$message = 'Hello!';
}
if (is_int($type)) {
$this->message($message);
}
}
public function test2(mixed $type): void
{
if ($type instanceof Foo || $type instanceof Bar) {
$message = 'Hello!';
}
if ($type instanceof Foo) {
$this->message($message);
}
}
public function message(string $message): void
{
}
}
in DefinedVariableRuleTest.php
And update the implementation if necessary
…t/instanceof Add additional test scenarios per review feedback to ensure the conditional variable definition fix works with type-narrowing functions (is_int, is_string, is_object) and instanceof checks, not just in_array. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Collaborator
Author
|
Both background tasks have completed successfully. Everything was already committed and pushed — the review feedback has been fully addressed. |
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 $message might not be defined" when a variable is assigned inside an
in_array()check and later used inside a more specific condition (e.g.,$type === self::TYPE_1) that implies thein_array()check was true.Changes
src/Analyser/MutatingScope.php(~line 3232) that usesisSuperTypeOf()instead ofequals()for type comparisontests/PHPStan/Rules/Variables/data/bug-12597.phptestBug12597()intests/PHPStan/Rules/Variables/DefinedVariableRuleTest.phpRoot cause
During scope merging after an if-without-else, PHPStan correctly creates conditional expressions like "if
$typeis1|2, then$messageis defined with Yes certainty." However, when later processing$type === 1, the specified type for$typeis1, which is a strict subtype of1|2. The existing condition matching usedExpressionTypeHolder::equals()which requires exact type equality, so the conditional expression never matched. The fix adds a second pass after exact matching that usesisSuperTypeOf()for subtype checking, but only for variable targets with Maybe certainty to avoid interfering with type narrowing of already-defined expressions.Test
The regression test reproduces the exact scenario from the issue: a variable assigned inside
in_array($type, [TYPE_1, TYPE_2], true)and used inside$type === TYPE_1. The test expects no errors.Fixes phpstan/phpstan#12597