diff --git a/packages/Php/src/Rector/String_/StringClassNameToClassConstantRector.php b/packages/Php/src/Rector/String_/StringClassNameToClassConstantRector.php index 22feb0661962..8a2fd4fdc87b 100644 --- a/packages/Php/src/Rector/String_/StringClassNameToClassConstantRector.php +++ b/packages/Php/src/Rector/String_/StringClassNameToClassConstantRector.php @@ -10,6 +10,7 @@ use Rector\RectorDefinition\CodeSample; use Rector\RectorDefinition\RectorDefinition; use Rector\Util\RectorStrings; +use ReflectionClass; /** * @see https://wiki.php.net/rfc/class_name_scalars @@ -21,6 +22,16 @@ final class StringClassNameToClassConstantRector extends AbstractRector */ private $classesToSkip = []; + /** + * @var string[] + */ + private $sensitiveExistingClasses = []; + + /** + * @var string[] + */ + private $sensitiveNonExistingClasses = []; + /** * @param string[] $classesToSkip */ @@ -80,7 +91,7 @@ public function getNodeTypes(): array public function refactor(Node $node): ?Node { $classLikeName = $node->value; - if (! $this->classLikeExists($classLikeName)) { + if (! $this->classLikeSensitiveExists($classLikeName)) { return null; } @@ -91,7 +102,33 @@ public function refactor(Node $node): ?Node return new ClassConstFetch(new FullyQualified($classLikeName), 'class'); } - private function classLikeExists(string $classLikeName): bool + private function classLikeSensitiveExists(string $classLikeName): bool + { + if (! $this->classLikeInsensitiveExists($classLikeName)) { + return false; + } + + // already known values + if (in_array($classLikeName, $this->sensitiveExistingClasses, true)) { + return true; + } + + if (in_array($classLikeName, $this->sensitiveNonExistingClasses, true)) { + return false; + } + + $classReflection = new ReflectionClass($classLikeName); + + if ($classLikeName !== $classReflection->getName()) { + $this->sensitiveNonExistingClasses[] = $classLikeName; + return false; + } + + $this->sensitiveExistingClasses[] = $classLikeName; + return true; + } + + private function classLikeInsensitiveExists(string $classLikeName): bool { if (class_exists($classLikeName)) { return true; diff --git a/packages/Php/tests/Rector/String_/StringClassNameToClassConstantRector/Fixture/skip_sensitive.php.inc b/packages/Php/tests/Rector/String_/StringClassNameToClassConstantRector/Fixture/skip_sensitive.php.inc new file mode 100644 index 000000000000..c614765ae38b --- /dev/null +++ b/packages/Php/tests/Rector/String_/StringClassNameToClassConstantRector/Fixture/skip_sensitive.php.inc @@ -0,0 +1,27 @@ + 'Exception']; + } +} + +?> +----- + \Exception::class]; + } +} + +?> diff --git a/packages/Php/tests/Rector/String_/StringClassNameToClassConstantRector/StringClassNameToClassConstantRectorTest.php b/packages/Php/tests/Rector/String_/StringClassNameToClassConstantRector/StringClassNameToClassConstantRectorTest.php index 9034d9acd470..c57661aea005 100644 --- a/packages/Php/tests/Rector/String_/StringClassNameToClassConstantRector/StringClassNameToClassConstantRectorTest.php +++ b/packages/Php/tests/Rector/String_/StringClassNameToClassConstantRector/StringClassNameToClassConstantRectorTest.php @@ -9,7 +9,11 @@ final class StringClassNameToClassConstantRectorTest extends AbstractRectorTestC { public function test(): void { - $this->doTestFiles([__DIR__ . '/Fixture/fixture.php.inc', __DIR__ . '/Fixture/skip_error.php.inc']); + $this->doTestFiles([ + __DIR__ . '/Fixture/fixture.php.inc', + __DIR__ . '/Fixture/skip_error.php.inc', + __DIR__ . '/Fixture/skip_sensitive.php.inc', + ]); } protected function getRectorClass(): string