From d9c1dcc7ce4a5284fe3530e011faf9c9c10e1166 Mon Sep 17 00:00:00 2001 From: Vladimir Chernyshev Date: Mon, 19 Mar 2018 17:57:41 +0200 Subject: [PATCH] Fix problems with leading '\' in FQCNs (#89) * Make some Reflection* classes independed of a leading '\' in FQCN * Make locators independed of a leading '\' in FQCN --- src/Locator/CallableLocator.php | 2 +- src/Locator/ComposerLocator.php | 2 +- src/LocatorInterface.php | 2 +- src/ReflectionClass.php | 2 +- src/ReflectionMethod.php | 2 +- src/ReflectionProperty.php | 2 +- tests/Locator/CallableLocatorTest.php | 3 ++- tests/Locator/ComposerLocatorTest.php | 4 ++++ tests/Stub/Issue44/Locator.php | 2 +- 9 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/Locator/CallableLocator.php b/src/Locator/CallableLocator.php index 9a55306f..4b536cd2 100644 --- a/src/Locator/CallableLocator.php +++ b/src/Locator/CallableLocator.php @@ -36,6 +36,6 @@ public function __construct(callable $callable) */ public function locateClass($className) { - return call_user_func($this->callable, $className); + return call_user_func($this->callable, ltrim($className, '\\')); } } diff --git a/src/Locator/ComposerLocator.php b/src/Locator/ComposerLocator.php index d402cae5..fd6de578 100644 --- a/src/Locator/ComposerLocator.php +++ b/src/Locator/ComposerLocator.php @@ -51,7 +51,7 @@ public function __construct(ClassLoader $loader = null) */ public function locateClass($className) { - $filePath = $this->loader->findFile($className); + $filePath = $this->loader->findFile(ltrim($className, '\\')); if (!empty($filePath)) { $filePath = PathResolver::realpath($filePath); } diff --git a/src/LocatorInterface.php b/src/LocatorInterface.php index 46738cba..3e147c27 100644 --- a/src/LocatorInterface.php +++ b/src/LocatorInterface.php @@ -19,7 +19,7 @@ interface LocatorInterface /** * Returns a path to the file for given class name * - * @param string $className Name of the class + * @param string $className Name of the class (with or without leading '\' FQCN) * * @return string|false Path to the file with given class or false if not found */ diff --git a/src/ReflectionClass.php b/src/ReflectionClass.php index fec99d7a..06dc2e93 100644 --- a/src/ReflectionClass.php +++ b/src/ReflectionClass.php @@ -33,7 +33,7 @@ class ReflectionClass extends InternalReflectionClass */ public function __construct($argument, ClassLike $classLikeNode = null) { - $fullClassName = is_object($argument) ? get_class($argument) : $argument; + $fullClassName = is_object($argument) ? get_class($argument) : ltrim($argument, '\\'); $namespaceParts = explode('\\', $fullClassName); $this->className = array_pop($namespaceParts); // Let's unset original read-only property to have a control over it via __get diff --git a/src/ReflectionMethod.php b/src/ReflectionMethod.php index 575f5a96..a295c98c 100644 --- a/src/ReflectionMethod.php +++ b/src/ReflectionMethod.php @@ -52,7 +52,7 @@ public function __construct( ReflectionClass $declaringClass = null ) { //for some reason, ReflectionMethod->getNamespaceName in php always returns '', so we shouldn't use it too - $this->className = $className; + $this->className = ltrim($className, '\\'); $this->declaringClass = $declaringClass; $this->functionLikeNode = $classMethodNode ?: ReflectionEngine::parseClassMethod($className, $methodName); diff --git a/src/ReflectionProperty.php b/src/ReflectionProperty.php index 22431b6e..413aab56 100644 --- a/src/ReflectionProperty.php +++ b/src/ReflectionProperty.php @@ -60,7 +60,7 @@ public function __construct( Property $propertyType = null, PropertyProperty $propertyNode = null ) { - $this->className = $className; + $this->className = ltrim($className, '\\'); if (!$propertyType || !$propertyNode) { list ($propertyType, $propertyNode) = ReflectionEngine::parseClassProperty($className, $propertyName); } diff --git a/tests/Locator/CallableLocatorTest.php b/tests/Locator/CallableLocatorTest.php index d6b310f4..975052a2 100644 --- a/tests/Locator/CallableLocatorTest.php +++ b/tests/Locator/CallableLocatorTest.php @@ -6,11 +6,12 @@ class CallableLocatorTest extends \PHPUnit_Framework_TestCase public function testLocateClass() { $callable = function ($class) { - return $class . '.php'; + return ltrim($class, '\\') . '.php'; }; $locator = new CallableLocator($callable); $this->assertSame('class.php', $locator->locateClass('class')); + $this->assertSame('class.php', $locator->locateClass('\class')); } } diff --git a/tests/Locator/ComposerLocatorTest.php b/tests/Locator/ComposerLocatorTest.php index e81691b6..d90a13ec 100644 --- a/tests/Locator/ComposerLocatorTest.php +++ b/tests/Locator/ComposerLocatorTest.php @@ -13,5 +13,9 @@ public function testLocateClass() $reflectionClass->getFileName(), $locator->locateClass(ReflectionClass::class) ); + $this->assertSame( + $reflectionClass->getFileName(), + $locator->locateClass('\\' . ReflectionClass::class) + ); } } diff --git a/tests/Stub/Issue44/Locator.php b/tests/Stub/Issue44/Locator.php index 050ec45f..03f8f790 100644 --- a/tests/Stub/Issue44/Locator.php +++ b/tests/Stub/Issue44/Locator.php @@ -11,7 +11,7 @@ class Locator implements LocatorInterface */ public function locateClass($className) { - if ($className === '\\Stub\\Issue44\\ClassWithNamespace') { + if (ltrim($className, '\\') === ClassWithNamespace::class) { return __DIR__ . '/ClassWithNamespace.php'; }