diff --git a/src/Rules/Classes/ClassConstantRule.php b/src/Rules/Classes/ClassConstantRule.php index 2d08602985..a14428d890 100644 --- a/src/Rules/Classes/ClassConstantRule.php +++ b/src/Rules/Classes/ClassConstantRule.php @@ -64,7 +64,11 @@ public function processNode(Node $node, Scope $scope): array } foreach ($constantNameScopes as $constantName => $constantScope) { - $errors = array_merge($errors, $this->processSingleClassConstFetch($constantScope, $node, $constantName)); + $errors = array_merge($errors, $this->processSingleClassConstFetch( + $constantScope, + $node, + (string) $constantName, // @phpstan-ignore cast.useless + )); } return $errors; diff --git a/src/Rules/Methods/CallMethodsRule.php b/src/Rules/Methods/CallMethodsRule.php index 8c01d0118a..984e5c8efe 100644 --- a/src/Rules/Methods/CallMethodsRule.php +++ b/src/Rules/Methods/CallMethodsRule.php @@ -47,7 +47,11 @@ public function processNode(Node $node, Scope $scope): array } foreach ($methodNameScopes as $methodName => $methodScope) { - $errors = array_merge($errors, $this->processSingleMethodCall($methodScope, $node, $methodName)); + $errors = array_merge($errors, $this->processSingleMethodCall( + $methodScope, + $node, + (string) $methodName, // @phpstan-ignore cast.useless + )); } return $errors; diff --git a/src/Rules/Methods/CallStaticMethodsRule.php b/src/Rules/Methods/CallStaticMethodsRule.php index 954c3a8669..04ffc64325 100644 --- a/src/Rules/Methods/CallStaticMethodsRule.php +++ b/src/Rules/Methods/CallStaticMethodsRule.php @@ -48,7 +48,11 @@ public function processNode(Node $node, Scope $scope): array } foreach ($methodNameScopes as $methodName => $methodScope) { - $errors = array_merge($errors, $this->processSingleMethodCall($methodScope, $node, $methodName)); + $errors = array_merge($errors, $this->processSingleMethodCall( + $methodScope, + $node, + (string) $methodName, // @phpstan-ignore cast.useless + )); } return $errors; diff --git a/src/Rules/Variables/DefinedVariableRule.php b/src/Rules/Variables/DefinedVariableRule.php index 2c7163434c..2056a89dbe 100644 --- a/src/Rules/Variables/DefinedVariableRule.php +++ b/src/Rules/Variables/DefinedVariableRule.php @@ -48,7 +48,11 @@ public function processNode(Node $node, Scope $scope): array } foreach ($variableNameScopes as $name => $variableScope) { - $errors = array_merge($errors, $this->processSingleVariable($variableScope, $node, $name)); + $errors = array_merge($errors, $this->processSingleVariable( + $variableScope, + $node, + (string) $name, // @phpstan-ignore cast.useless + )); } return $errors; diff --git a/tests/PHPStan/Analyser/AnalyserIntegrationTest.php b/tests/PHPStan/Analyser/AnalyserIntegrationTest.php index 156b26cffa..c94a5cff18 100644 --- a/tests/PHPStan/Analyser/AnalyserIntegrationTest.php +++ b/tests/PHPStan/Analyser/AnalyserIntegrationTest.php @@ -1570,6 +1570,20 @@ public function testBug12800(): void $this->assertNoErrors($errors); } + public function testBug12949(): void + { + // Fetching class constants with a dynamic name is supported only on PHP 8.3 and later + if (PHP_VERSION_ID < 80300) { + $this->markTestSkipped('Test requires PHP 8.3.'); + } + + $errors = $this->runAnalyse(__DIR__ . '/data/bug-12949.php'); + $this->assertCount(3, $errors); + $this->assertSame('Call to an undefined method object::0().', $errors[0]->getMessage()); + $this->assertSame('Call to an undefined static method object::0().', $errors[1]->getMessage()); + $this->assertSame('Access to undefined constant object::0.', $errors[2]->getMessage()); + } + /** * @param string[]|null $allAnalysedFiles * @return Error[] diff --git a/tests/PHPStan/Analyser/data/bug-12949.php b/tests/PHPStan/Analyser/data/bug-12949.php new file mode 100644 index 0000000000..eeafccb0de --- /dev/null +++ b/tests/PHPStan/Analyser/data/bug-12949.php @@ -0,0 +1,19 @@ +{$b}(); + $o::{$b}(); + echo $o::{$b}; + + echo ""; +}