diff --git a/libraries/loader.php b/libraries/loader.php index 5adca189bf340..ef2bb36840c77 100644 --- a/libraries/loader.php +++ b/libraries/loader.php @@ -438,6 +438,9 @@ public static function registerNamespace($namespace, $path, $reset = false, $pre throw new RuntimeException('Library path ' . $path . ' cannot be found.', 500); } + // Trim leading and trailing backslashes from namespace, allowing "\Parent\Child", "Parent\Child\" and "\Parent\Child\" to be treated the same way. + $namespace = trim($namespace, '\\'); + // If the namespace is not yet registered or we have an explicit reset flag then set the path. if ($reset || !isset(self::$namespaces[$type][$namespace])) { @@ -533,10 +536,10 @@ public static function loadByPsr4($class) // Loop through registered namespaces until we find a match. foreach (self::$namespaces['psr4'] as $ns => $paths) { - $nsPath = trim(str_replace('\\', DIRECTORY_SEPARATOR, $ns), DIRECTORY_SEPARATOR); - - if (strpos($class, $ns) === 0) + if (strpos($class, "{$ns}\\") === 0) { + $nsPath = trim(str_replace('\\', DIRECTORY_SEPARATOR, $ns), DIRECTORY_SEPARATOR); + // Loop through paths registered to this namespace until we find a match. foreach ($paths as $path) { diff --git a/tests/unit/stubs/DummyNamespace/DummyClass.php b/tests/unit/stubs/DummyNamespace/DummyClass.php new file mode 100644 index 0000000000000..f2484e939dd62 --- /dev/null +++ b/tests/unit/stubs/DummyNamespace/DummyClass.php @@ -0,0 +1,29 @@ +assertEquals('Original Override Class', $oldClass->getName()); } + /** + * Tests the JLoader::loadByPsr4 method. + * + * @return void + * + * @since __DEPLOY_VERSION__ + */ + public function testLoadByPsr4() + { + // Register namespace at first. Odd leading and trailing backslashes must be automatically removed from namespace + JLoader::registerNamespace('\\DummyNamespace\\', JPATH_TEST_STUBS . '/DummyNamespace', $reset = true, $prepend = false, $type = 'psr4'); + + $this->assertThat(JLoader::loadByPsr4('DummyNamespace\DummyClass'), $this->isTrue(), 'Tests that the class file was loaded.'); + } + /** * Tests the JLoader::registerAlias method if the alias is loaded when the original class is loaded. * @@ -487,6 +502,32 @@ public function testRegisterNamespaceException() JLoader::registerNamespace('Color', 'dummy'); } + /** + * Tests the JLoader::registerNamespace method for namespace trimming of leading and trailing backslashes. + * + * @return void + * + * @since 12.3 + */ + public function testRegisterNamespaceTrimming() + { + // Try registering namespace with leading backslash. + $path = JPATH_TEST_STUBS . '/discover1'; + JLoader::registerNamespace('\\discover1', $path); + + $namespaces = JLoader::getNamespaces(); + + $this->assertContains($path, $namespaces['discover1']); + + // Try registering namespace with trailing backslash. + $path = JPATH_TEST_STUBS . '/discover2'; + JLoader::registerNamespace('discover2\\', $path); + + $namespaces = JLoader::getNamespaces(); + + $this->assertContains($path, $namespaces['discover2']); + } + /** * Tests the JLoader::registerPrefix method. *