Skip to content

Commit 81efc72

Browse files
committed
Fix class constant scope
1 parent ebb3b6f commit 81efc72

File tree

3 files changed

+61
-7
lines changed

3 files changed

+61
-7
lines changed

src/Rules/Classes/ClassConstantRule.php

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
namespace PHPStan\Rules\Classes;
44

55
use PhpParser\Node;
6+
use PhpParser\Node\Expr\BinaryOp\Identical;
67
use PhpParser\Node\Expr\ClassConstFetch;
8+
use PhpParser\Node\Scalar\String_;
79
use PHPStan\Analyser\NullsafeOperatorHelper;
810
use PHPStan\Analyser\Scope;
911
use PHPStan\Internal\SprintfHelper;
@@ -21,7 +23,6 @@
2123
use PHPStan\Type\Type;
2224
use PHPStan\Type\TypeCombinator;
2325
use PHPStan\Type\VerbosityLevel;
24-
use function array_map;
2526
use function array_merge;
2627
use function in_array;
2728
use function sprintf;
@@ -51,14 +52,18 @@ public function processNode(Node $node, Scope $scope): array
5152
{
5253
$errors = [];
5354
if ($node->name instanceof Node\Identifier) {
54-
$constantNames = [$node->name->name];
55+
$constantNameScopes = [$node->name->name => $scope];
5556
} else {
56-
$fetchType = $scope->getType($node->name);
57-
$constantNames = array_map(static fn ($type): string => $type->getValue(), $fetchType->getConstantStrings());
57+
$nameType = $scope->getType($node->name);
58+
$constantNameScopes = [];
59+
foreach ($nameType->getConstantStrings() as $constantString) {
60+
$name = $constantString->getValue();
61+
$constantNameScopes[$name] = $scope->filterByTruthyValue(new Identical($node->name, new String_($name)));
62+
}
5863
}
5964

60-
foreach ($constantNames as $constantName) {
61-
$errors = array_merge($errors, $this->processSingleClassConstFetch($scope, $node, $constantName));
65+
foreach ($constantNameScopes as $constantName => $constantScope) {
66+
$errors = array_merge($errors, $this->processSingleClassConstFetch($constantScope, $node, $constantName));
6267
}
6368

6469
return $errors;

tests/PHPStan/Rules/Classes/ClassConstantRuleTest.php

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -452,6 +452,30 @@ public function testDynamicAccess(): void
452452
'Access to undefined constant ClassConstantDynamicAccess\Foo::BUZ.',
453453
20,
454454
],
455+
[
456+
'Access to undefined constant ClassConstantDynamicAccess\Foo::FOO.',
457+
37,
458+
],
459+
[
460+
'Access to undefined constant ClassConstantDynamicAccess\Foo::BUZ.',
461+
39,
462+
],
463+
[
464+
'Access to undefined constant ClassConstantDynamicAccess\Foo::QUX.',
465+
41,
466+
],
467+
[
468+
'Access to undefined constant ClassConstantDynamicAccess\Foo::QUX.',
469+
44,
470+
],
471+
[
472+
'Access to undefined constant ClassConstantDynamicAccess\Foo::BUZ.',
473+
44,
474+
],
475+
[
476+
'Access to undefined constant ClassConstantDynamicAccess\Foo::FOO.',
477+
44,
478+
],
455479
]);
456480
}
457481

tests/PHPStan/Rules/Classes/data/dynamic-constant-access.php

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
final class Foo
66
{
77

8-
private const BAR = 'FOO';
8+
private const BAR = 'BAR';
99

1010
/** @var 'FOO'|'BAR'|'BUZ' */
1111
public $name;
@@ -20,4 +20,29 @@ public function test(string $string, object $obj): void
2020
echo self::{$this->name};
2121
}
2222

23+
public function testScope(): void
24+
{
25+
$name1 = 'FOO';
26+
$rand = rand();
27+
if ($rand === 1) {
28+
$foo = 1;
29+
$name = $name1;
30+
} elseif ($rand === 2) {
31+
$name = 'BUZ';
32+
} else {
33+
$name = 'QUX';
34+
}
35+
36+
if ($name === 'FOO') {
37+
echo self::{$name};
38+
} elseif ($name === 'BUZ') {
39+
echo self::{$name};
40+
} else {
41+
echo self::{$name};
42+
}
43+
44+
echo self::{$name};
45+
}
46+
47+
2348
}

0 commit comments

Comments
 (0)