Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/Analyser/MutatingScope.php
Original file line number Diff line number Diff line change
Expand Up @@ -4094,6 +4094,14 @@ private function createConditionalExpressions(
continue;
}

if (
array_key_exists($exprString, $newVariableTypes)
&& $newVariableTypes[$exprString]->equalTypes($holder)
&& !$newVariableTypes[$exprString]->getCertainty()->equals($holder->getCertainty())
) {
continue;
}

unset($newVariableTypes[$exprString]);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ public function locateIdentifier(Reflector $reflector, Identifier $identifier):
return null;
}

[$reflectionCacheKey, $variableCacheKey] = $this->getCacheKeys($file, $identifier); // @phpstan-ignore variable.undefined
[$reflectionCacheKey, $variableCacheKey] = $this->getCacheKeys($file, $identifier);
$classReflection = $this->nodeToReflection($reflector, $fetchedClassNode);
$this->cache->save($reflectionCacheKey, $variableCacheKey, $classReflection->exportToCache());

Expand Down Expand Up @@ -171,7 +171,7 @@ public function locateIdentifier(Reflector $reflector, Identifier $identifier):
return null;
}

[$reflectionCacheKey, $variableCacheKey] = $this->getCacheKeys($file, $identifier); // @phpstan-ignore variable.undefined
[$reflectionCacheKey, $variableCacheKey] = $this->getCacheKeys($file, $identifier);
$constantReflection = $this->nodeToReflection(
$reflector,
$fetchedConstantNode,
Expand Down
19 changes: 19 additions & 0 deletions tests/PHPStan/Rules/Variables/DefinedVariableRuleTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -1333,4 +1333,23 @@ public function testBug5477(): void
$this->analyse([__DIR__ . '/data/bug-5477.php'], []);
}

public function testBug14117(): void
{
$this->cliArgumentsVariablesRegistered = true;
$this->polluteScopeWithLoopInitialAssignments = false;
$this->checkMaybeUndefinedVariables = true;
$this->polluteScopeWithAlwaysIterableForeach = true;

$this->analyse([__DIR__ . '/data/bug-14117.php'], [
[
'Variable $value might not be defined.',
33,
],
[
'Variable $value might not be defined.',
49,
],
]);
}

}
51 changes: 51 additions & 0 deletions tests/PHPStan/Rules/Variables/data/bug-14117.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<?php declare(strict_types = 1);

namespace Bug14117;

function foo(): void {
$key = rand(0, 2);

if ($key === 2) {
$value = 'test';
}

if ($key === 1) {
$value = 'test';
}

if ($key === 1) {
echo $value;
}
}

function bar(): void {
$key = rand(0, 2);

if ($key === 2) {
$value = 'two';
}

if ($key === 1) {
$value = 'one';
}

if ($key === 2) {
echo $value;
}
}

function baz(): void {
Copy link
Copy Markdown
Contributor

@staabm staabm Mar 4, 2026

Choose a reason for hiding this comment

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

in this file I added a few more tests which e.g. also check the interaction with unset().

while doing so I found a case which does not yet work: phpstan/phpstan#14227

$key = rand(0, 3);

if ($key === 1) {
$value = 'one';
}

if ($key === 2) {
$value = 'two';
}

if ($key === 3) {
echo $value; // this one SHOULD report "might not be defined" because $key === 3 doesn't guarantee either earlier block ran
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.

Technically the variable should be reported as always undefined...

}
}
Loading