From 0ccc9805f54ca46d4ea9fdda026b0779e858c616 Mon Sep 17 00:00:00 2001 From: Justin Hileman Date: Tue, 19 Oct 2010 15:45:04 -0400 Subject: [PATCH] Fix UniversalClassLoader issues with leading slashes. This fixes a bug in UniversalClassLoader when attempting to autoload class names with leading slashes: $namespacedClass = "\\Foo\\Bar"; $pearlikeClass = "\\Foo_Bar"; $namespaced = new $namespacedClass(); $pearlike = new $pearlikeClass(); `UniversalClassLoader::loadClass()` was unable to load PEAR-like classes with leading slashes because it found the slash and assumed that the requested class was namespaced. It was unable to load namespaced classes with leading slashes because it would look them up in the autoloader's registered namespaces, and was unable to match '\Foo' to 'Foo'. One (ugly) workaround for the namespaced classes was to register all namespaces twice: $loader->registerNamespaces(array( 'Foo' => __DIR__ . '/lib', '\Foo' => __DIR__ . '/lib', )); But that's not very pretty, nor does it solve the bug with PEAR-like classes. Stripping the leading slash before trying to autoload allows UniversalClassLoader to load both namespaced and PEAR-like classes. --- .../HttpFoundation/UniversalClassLoader.php | 4 ++ .../Fixtures/Namespaced/Bar.php | 7 ++++ .../Fixtures/Namespaced/Foo.php | 7 ++++ .../HttpFoundation/Fixtures/Pearlike/Bar.php | 5 +++ .../HttpFoundation/Fixtures/Pearlike/Foo.php | 5 +++ .../UniversalClassLoaderTest.php | 41 +++++++++++++++++++ 6 files changed, 69 insertions(+) create mode 100644 tests/Symfony/Tests/Component/HttpFoundation/Fixtures/Namespaced/Bar.php create mode 100644 tests/Symfony/Tests/Component/HttpFoundation/Fixtures/Namespaced/Foo.php create mode 100644 tests/Symfony/Tests/Component/HttpFoundation/Fixtures/Pearlike/Bar.php create mode 100644 tests/Symfony/Tests/Component/HttpFoundation/Fixtures/Pearlike/Foo.php create mode 100644 tests/Symfony/Tests/Component/HttpFoundation/UniversalClassLoaderTest.php diff --git a/src/Symfony/Component/HttpFoundation/UniversalClassLoader.php b/src/Symfony/Component/HttpFoundation/UniversalClassLoader.php index 0cfe1bcf7f8c..bbfd6a91591f 100644 --- a/src/Symfony/Component/HttpFoundation/UniversalClassLoader.php +++ b/src/Symfony/Component/HttpFoundation/UniversalClassLoader.php @@ -123,6 +123,10 @@ public function register() */ public function loadClass($class) { + if ('\\' === $class[0]) { + $class = substr($class, 1); + } + if (false !== ($pos = strripos($class, '\\'))) { // namespaced class name $namespace = substr($class, 0, $pos); diff --git a/tests/Symfony/Tests/Component/HttpFoundation/Fixtures/Namespaced/Bar.php b/tests/Symfony/Tests/Component/HttpFoundation/Fixtures/Namespaced/Bar.php new file mode 100644 index 000000000000..c16eef7b080c --- /dev/null +++ b/tests/Symfony/Tests/Component/HttpFoundation/Fixtures/Namespaced/Bar.php @@ -0,0 +1,7 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Tests\Component\HttpFoundation; + +use Symfony\Component\HttpFoundation\UniversalClassLoader; + +class UniversalClassLoaderTest extends \PHPUnit_Framework_TestCase +{ + /** + * @covers Symfony\Component\HttpFoundation\UniversalClassLoader::loadClass + * @dataProvider testClassProvider + */ + public function testLoadClass($className, $testClassName, $message) + { + $loader = new UniversalClassLoader(); + $loader->registerNamespace('Namespaced', __DIR__ . DIRECTORY_SEPARATOR . 'Fixtures'); + $loader->registerPrefix('Pearlike_', __DIR__ . DIRECTORY_SEPARATOR . 'Fixtures'); + $loader->loadClass($testClassName); + $this->assertTrue(class_exists($className), $message); + } + + public static function testClassProvider() + { + return array( + array('\\Namespaced\\Foo', 'Namespaced\\Foo', '->loadClass() loads Namespaced\Foo class'), + array('\\Pearlike_Foo', 'Pearlike_Foo', '->loadClass() loads Pearlike_Foo class'), + array('\\Namespaced\\Bar', '\\Namespaced\\Bar', '->loadClass() loads Namespaced\Bar class with a leading slash'), + array('\\Pearlike_Bar', '\\Pearlike_Bar', '->loadClass() loads Pearlike_Bar class with a leading slash'), + ); + } +} +