Compare commits

..

12 Commits
3.0 ... v2.7.30

Author SHA1 Message Date
Fabien Potencier
8bfdaa2e7a Using FQ name for PHP_VERSION_ID 2017-06-01 13:44:56 -07:00
Christian Flothmann
fdb4806d2e fail when detecting risky tests 2017-04-12 09:39:27 +02:00
Fabien Potencier
b6e2bb88a8 fixed Composer constraints 2017-02-18 10:28:08 -08:00
Peter Rehm
64d2af707a Update to PHPUnit namespaces 2017-02-18 08:02:39 -08:00
Fabien Potencier
44816c55e9 fixed CS 2017-01-20 08:54:19 -08:00
Grégoire Pineau
1108382429 [ClassLoader] Throw an exception if the cache is not writeable 2017-01-09 15:44:50 +01:00
Fabien Potencier
2e19afbcc7 updated LICENSE year 2017-01-02 12:30:00 -08:00
Nicolas Grekas
65ac4dbf59 [ClassLoader] Use only forward slashes in generated class map 2016-11-29 09:16:08 +01:00
Giorgio Premi
c060834942 [ClassLoader] Fix ClassCollectionLoader inlining with __halt_compiler 2016-11-15 04:22:02 -05:00
Nicolas Grekas
886fe1940b Enhance GAE compat by removing some realpath() 2016-10-27 11:13:40 +02:00
Nicolas Grekas
8ec0c38b8d [ClassLoader] Fix ClassCollectionLoader inlining with declare(strict_types=1) 2016-09-05 21:55:26 +02:00
Nicolas Grekas
df77b1499c [ClassLoader] Fix tests 2016-08-23 11:26:23 +02:00
42 changed files with 1420 additions and 69 deletions

View File

@@ -16,8 +16,8 @@ namespace Symfony\Component\ClassLoader;
*
* It expects an object implementing a findFile method to find the file. This
* allows using it as a wrapper around the other loaders of the component (the
* ClassLoader for instance) but also around any other autoloaders following
* this convention (the Composer one for instance).
* ClassLoader and the UniversalClassLoader for instance) but also around any
* other autoloaders following this convention (the Composer one for instance).
*
* // with a Symfony autoloader
* use Symfony\Component\ClassLoader\ClassLoader;

103
ApcUniversalClassLoader.php Normal file
View File

@@ -0,0 +1,103 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\ClassLoader;
@trigger_error('The '.__NAMESPACE__.'\ApcUniversalClassLoader class is deprecated since version 2.7 and will be removed in 3.0. Use the Symfony\Component\ClassLoader\ApcClassLoader class instead.', E_USER_DEPRECATED);
/**
* ApcUniversalClassLoader implements a "universal" autoloader cached in APC for PHP 5.3.
*
* It is able to load classes that use either:
*
* * The technical interoperability standards for PHP 5.3 namespaces and
* class names (https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md);
*
* * The PEAR naming convention for classes (http://pear.php.net/).
*
* Classes from a sub-namespace or a sub-hierarchy of PEAR classes can be
* looked for in a list of locations to ease the vendoring of a sub-set of
* classes for large projects.
*
* Example usage:
*
* require 'vendor/symfony/src/Symfony/Component/ClassLoader/UniversalClassLoader.php';
* require 'vendor/symfony/src/Symfony/Component/ClassLoader/ApcUniversalClassLoader.php';
*
* use Symfony\Component\ClassLoader\ApcUniversalClassLoader;
*
* $loader = new ApcUniversalClassLoader('apc.prefix.');
*
* // register classes with namespaces
* $loader->registerNamespaces(array(
* 'Symfony\Component' => __DIR__.'/component',
* 'Symfony' => __DIR__.'/framework',
* 'Sensio' => array(__DIR__.'/src', __DIR__.'/vendor'),
* ));
*
* // register a library using the PEAR naming convention
* $loader->registerPrefixes(array(
* 'Swift_' => __DIR__.'/Swift',
* ));
*
* // activate the autoloader
* $loader->register();
*
* In this example, if you try to use a class in the Symfony\Component
* namespace or one of its children (Symfony\Component\Console for instance),
* the autoloader will first look for the class under the component/
* directory, and it will then fallback to the framework/ directory if not
* found before giving up.
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Kris Wallsmith <kris@symfony.com>
*
* @deprecated since version 2.4, to be removed in 3.0.
* Use the {@link ClassLoader} class instead.
*/
class ApcUniversalClassLoader extends UniversalClassLoader
{
private $prefix;
/**
* Constructor.
*
* @param string $prefix A prefix to create a namespace in APC
*
* @throws \RuntimeException
*/
public function __construct($prefix)
{
if (!function_exists('apcu_fetch')) {
throw new \RuntimeException('Unable to use ApcUniversalClassLoader as APC is not enabled.');
}
$this->prefix = $prefix;
}
/**
* Finds a file by class name while caching lookups to APC.
*
* @param string $class A class name to resolve to file
*
* @return string|null The path, if found
*/
public function findFile($class)
{
$file = apcu_fetch($this->prefix.$class, $success);
if (!$success) {
apcu_store($this->prefix.$class, $file = parent::findFile($class) ?: null);
}
return $file;
}
}

View File

@@ -1,14 +1,6 @@
CHANGELOG
=========
3.0.0
-----
* The DebugClassLoader class has been removed
* The DebugUniversalClassLoader class has been removed
* The UniversalClassLoader class has been removed
* The ApcUniversalClassLoader class has been removed
2.4.0
-----

View File

@@ -44,7 +44,10 @@ class ClassCollectionLoader
self::$loaded[$name] = true;
if ($adaptive) {
$declared = array_merge(get_declared_classes(), get_declared_interfaces(), get_declared_traits());
$declared = array_merge(get_declared_classes(), get_declared_interfaces());
if (function_exists('get_declared_traits')) {
$declared = array_merge($declared, get_declared_traits());
}
// don't include already declared classes
$classes = array_diff($classes, $declared);
@@ -55,6 +58,11 @@ class ClassCollectionLoader
$classes = array_unique($classes);
// cache the core classes
if (!is_dir($cacheDir) && !@mkdir($cacheDir, 0777, true) && !is_dir($cacheDir)) {
throw new \RuntimeException(sprintf('Class Collection Loader was not able to create directory "%s"', $cacheDir));
}
$cacheDir = rtrim(realpath($cacheDir) ?: $cacheDir, '/'.DIRECTORY_SEPARATOR);
$cache = $cacheDir.'/'.$name.$extension;
// auto-reload
@@ -90,9 +98,23 @@ class ClassCollectionLoader
return;
}
if (!$adaptive) {
$declared = array_merge(get_declared_classes(), get_declared_interfaces(), get_declared_traits());
$declared = array_merge(get_declared_classes(), get_declared_interfaces());
if (function_exists('get_declared_traits')) {
$declared = array_merge($declared, get_declared_traits());
}
}
$spacesRegex = '(?:\s*+(?:(?:\#|//)[^\n]*+\n|/\*(?:(?<!\*/).)++)?+)*+';
$dontInlineRegex = <<<REGEX
'(?:
^<\?php\s.declare.\(.strict_types.=.1.\).;
| \b__halt_compiler.\(.\)
| \b__(?:DIR|FILE)__\b
)'isx
REGEX;
$dontInlineRegex = str_replace('.', $spacesRegex, $dontInlineRegex);
$cacheDir = explode('/', str_replace(DIRECTORY_SEPARATOR, '/', $cacheDir));
$files = array();
$content = '';
foreach (self::getOrderedClasses($classes) as $class) {
@@ -100,25 +122,40 @@ class ClassCollectionLoader
continue;
}
$files[] = $class->getFileName();
$files[] = $file = $class->getFileName();
$c = file_get_contents($file);
$c = preg_replace(array('/^\s*<\?php/', '/\?>\s*$/'), '', file_get_contents($class->getFileName()));
if (preg_match($dontInlineRegex, $c)) {
$file = explode('/', str_replace(DIRECTORY_SEPARATOR, '/', $file));
// fakes namespace declaration for global code
if (!$class->inNamespace()) {
$c = "\nnamespace\n{\n".$c."\n}\n";
for ($i = 0; isset($file[$i], $cacheDir[$i]); ++$i) {
if ($file[$i] !== $cacheDir[$i]) {
break;
}
}
if (1 >= $i) {
$file = var_export(implode('/', $file), true);
} else {
$file = array_slice($file, $i);
$file = str_repeat('../', count($cacheDir) - $i).implode('/', $file);
$file = '__DIR__.'.var_export('/'.$file, true);
}
$c = "\nnamespace {require $file;}";
} else {
$c = preg_replace(array('/^\s*<\?php/', '/\?>\s*$/'), '', $c);
// fakes namespace declaration for global code
if (!$class->inNamespace()) {
$c = "\nnamespace\n{\n".$c."\n}\n";
}
$c = self::fixNamespaceDeclarations('<?php '.$c);
$c = preg_replace('/^\s*<\?php/', '', $c);
}
$c = self::fixNamespaceDeclarations('<?php '.$c);
$c = preg_replace('/^\s*<\?php/', '', $c);
$content .= $c;
}
// cache the core classes
if (!is_dir($cacheDir) && !@mkdir($cacheDir, 0777, true) && !is_dir($cacheDir)) {
throw new \RuntimeException(sprintf('Class Collection Loader was not able to create directory "%s"', $cacheDir));
}
self::writeCacheFile($cache, '<?php '.$content);
if ($autoReload) {
@@ -195,7 +232,7 @@ class ClassCollectionLoader
$output .= self::compressCode($rawChunk);
if (PHP_VERSION_ID >= 70000) {
if (\PHP_VERSION_ID >= 70000) {
// PHP 7 memory manager will not release after token_get_all(), see https://bugs.php.net/70098
unset($tokens, $rawChunk);
gc_mem_caches();
@@ -238,7 +275,13 @@ class ClassCollectionLoader
*/
private static function writeCacheFile($file, $content)
{
$tmpFile = tempnam(dirname($file), basename($file));
$dir = dirname($file);
if (!is_writable($dir)) {
throw new \RuntimeException(sprintf('Cache directory "%s" is not writable.', $dir));
}
$tmpFile = tempnam($dir, basename($file));
if (false !== @file_put_contents($tmpFile, $content) && @rename($tmpFile, $file)) {
@chmod($file, 0666 & ~umask());
@@ -292,10 +335,12 @@ class ClassCollectionLoader
$traits = array();
foreach ($classes as $c) {
foreach (self::resolveDependencies(self::computeTraitDeps($c), $c) as $trait) {
if ($trait !== $c) {
$traits[] = $trait;
if (method_exists('ReflectionClass', 'getTraits')) {
foreach ($classes as $c) {
foreach (self::resolveDependencies(self::computeTraitDeps($c), $c) as $trait) {
if ($trait !== $c) {
$traits[] = $trait;
}
}
}
}

View File

@@ -11,6 +11,14 @@
namespace Symfony\Component\ClassLoader;
if (!defined('SYMFONY_TRAIT')) {
if (\PHP_VERSION_ID >= 50400) {
define('SYMFONY_TRAIT', T_TRAIT);
} else {
define('SYMFONY_TRAIT', 0);
}
}
/**
* ClassMapGenerator.
*
@@ -56,7 +64,7 @@ class ClassMapGenerator
continue;
}
$path = $file->getRealPath();
$path = $file->getRealPath() ?: $file->getPathname();
if (pathinfo($path, PATHINFO_EXTENSION) !== 'php') {
continue;
@@ -64,7 +72,7 @@ class ClassMapGenerator
$classes = self::findClasses($path);
if (PHP_VERSION_ID >= 70000) {
if (\PHP_VERSION_ID >= 70000) {
// PHP 7 memory manager will not release after token_get_all(), see https://bugs.php.net/70098
gc_mem_caches();
}
@@ -114,7 +122,7 @@ class ClassMapGenerator
break;
case T_CLASS:
case T_INTERFACE:
case T_TRAIT:
case SYMFONY_TRAIT:
// Skip usage of ::class constant
$isClassConstant = false;
for ($j = $i - 1; $j > 0; --$j) {

120
DebugClassLoader.php Normal file
View File

@@ -0,0 +1,120 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\ClassLoader;
@trigger_error('The '.__NAMESPACE__.'\DebugClassLoader class is deprecated since version 2.4 and will be removed in 3.0. Use the Symfony\Component\Debug\DebugClassLoader class instead.', E_USER_DEPRECATED);
/**
* Autoloader checking if the class is really defined in the file found.
*
* The DebugClassLoader will wrap all registered autoloaders providing a
* findFile method and will throw an exception if a file is found but does
* not declare the class.
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Christophe Coevoet <stof@notk.org>
*
* @deprecated since version 2.4, to be removed in 3.0.
* Use {@link \Symfony\Component\Debug\DebugClassLoader} instead.
*/
class DebugClassLoader
{
private $classFinder;
/**
* Constructor.
*
* @param object $classFinder
*/
public function __construct($classFinder)
{
$this->classFinder = $classFinder;
}
/**
* Gets the wrapped class loader.
*
* @return object a class loader instance
*/
public function getClassLoader()
{
return $this->classFinder;
}
/**
* Replaces all autoloaders implementing a findFile method by a DebugClassLoader wrapper.
*/
public static function enable()
{
if (!is_array($functions = spl_autoload_functions())) {
return;
}
foreach ($functions as $function) {
spl_autoload_unregister($function);
}
foreach ($functions as $function) {
if (is_array($function) && !$function[0] instanceof self && method_exists($function[0], 'findFile')) {
$function = array(new static($function[0]), 'loadClass');
}
spl_autoload_register($function);
}
}
/**
* Unregisters this instance as an autoloader.
*/
public function unregister()
{
spl_autoload_unregister(array($this, 'loadClass'));
}
/**
* Finds a file by class name.
*
* @param string $class A class name to resolve to file
*
* @return string|null
*/
public function findFile($class)
{
return $this->classFinder->findFile($class) ?: null;
}
/**
* Loads the given class or interface.
*
* @param string $class The name of the class
*
* @return bool|null True, if loaded
*
* @throws \RuntimeException
*/
public function loadClass($class)
{
if ($file = $this->classFinder->findFile($class)) {
require $file;
if (!class_exists($class, false) && !interface_exists($class, false) && (!function_exists('trait_exists') || !trait_exists($class, false))) {
if (false !== strpos($class, '/')) {
throw new \RuntimeException(sprintf('Trying to autoload a class with an invalid name "%s". Be careful that the namespace separator is "\" in PHP, not "/".', $class));
}
throw new \RuntimeException(sprintf('The autoloader expected class "%s" to be defined in file "%s". The file was found but the class was not in it, the class name or namespace probably has a typo.', $class, $file));
}
return true;
}
}
}

View File

@@ -0,0 +1,68 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\ClassLoader;
@trigger_error('The '.__NAMESPACE__.'\DebugUniversalClassLoader class is deprecated since version 2.4 and will be removed in 3.0. Use the Symfony\Component\Debug\DebugClassLoader class instead.', E_USER_DEPRECATED);
/**
* Checks that the class is actually declared in the included file.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @deprecated since version 2.4, to be removed in 3.0.
* Use the {@link \Symfony\Component\Debug\DebugClassLoader} class instead.
*/
class DebugUniversalClassLoader extends UniversalClassLoader
{
/**
* Replaces all regular UniversalClassLoader instances by a DebugUniversalClassLoader ones.
*/
public static function enable()
{
if (!is_array($functions = spl_autoload_functions())) {
return;
}
foreach ($functions as $function) {
spl_autoload_unregister($function);
}
foreach ($functions as $function) {
if (is_array($function) && $function[0] instanceof UniversalClassLoader) {
$loader = new static();
$loader->registerNamespaceFallbacks($function[0]->getNamespaceFallbacks());
$loader->registerPrefixFallbacks($function[0]->getPrefixFallbacks());
$loader->registerNamespaces($function[0]->getNamespaces());
$loader->registerPrefixes($function[0]->getPrefixes());
$loader->useIncludePath($function[0]->getUseIncludePath());
$function[0] = $loader;
}
spl_autoload_register($function);
}
}
/**
* {@inheritdoc}
*/
public function loadClass($class)
{
if ($file = $this->findFile($class)) {
require $file;
if (!class_exists($class, false) && !interface_exists($class, false) && (!function_exists('trait_exists') || !trait_exists($class, false))) {
throw new \RuntimeException(sprintf('The autoloader expected class "%s" to be defined in file "%s". The file was found but the class was not in it, the class name or namespace probably has a typo.', $class, $file));
}
}
}
}

View File

@@ -1,4 +1,4 @@
Copyright (c) 2004-2016 Fabien Potencier
Copyright (c) 2004-2017 Fabien Potencier
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@@ -45,7 +45,8 @@ class Psr4ClassLoader
{
$class = ltrim($class, '\\');
foreach ($this->prefixes as list($currentPrefix, $currentBaseDir)) {
foreach ($this->prefixes as $current) {
list($currentPrefix, $currentBaseDir) = $current;
if (0 === strpos($class, $currentPrefix)) {
$classWithoutPrefix = substr($class, strlen($currentPrefix));
$file = $currentBaseDir.str_replace('\\', DIRECTORY_SEPARATOR, $classWithoutPrefix).'.php';

View File

@@ -11,10 +11,11 @@
namespace Symfony\Component\ClassLoader\Tests;
use PHPUnit\Framework\TestCase;
use Symfony\Component\ClassLoader\ApcClassLoader;
use Symfony\Component\ClassLoader\ClassLoader;
class ApcClassLoaderTest extends \PHPUnit_Framework_TestCase
class ApcClassLoaderTest extends TestCase
{
protected function setUp()
{

View File

@@ -11,6 +11,7 @@
namespace Symfony\Component\ClassLoader\Tests;
use PHPUnit\Framework\TestCase;
use Symfony\Component\ClassLoader\ClassCollectionLoader;
require_once __DIR__.'/Fixtures/ClassesWithParents/GInterface.php';
@@ -18,8 +19,11 @@ require_once __DIR__.'/Fixtures/ClassesWithParents/CInterface.php';
require_once __DIR__.'/Fixtures/ClassesWithParents/B.php';
require_once __DIR__.'/Fixtures/ClassesWithParents/A.php';
class ClassCollectionLoaderTest extends \PHPUnit_Framework_TestCase
class ClassCollectionLoaderTest extends TestCase
{
/**
* @requires PHP 5.4
*/
public function testTraitDependencies()
{
require_once __DIR__.'/Fixtures/deps/traits.php';
@@ -28,14 +32,14 @@ class ClassCollectionLoaderTest extends \PHPUnit_Framework_TestCase
$m = $r->getMethod('getOrderedClasses');
$m->setAccessible(true);
$ordered = $m->invoke('Symfony\Component\ClassLoader\ClassCollectionLoader', array('CTFoo'));
$ordered = $m->invoke(null, array('CTFoo'));
$this->assertEquals(
array('TD', 'TC', 'TB', 'TA', 'TZ', 'CTFoo'),
array_map(function ($class) { return $class->getName(); }, $ordered)
);
$ordered = $m->invoke('Symfony\Component\ClassLoader\ClassCollectionLoader', array('CTBar'));
$ordered = $m->invoke(null, array('CTBar'));
$this->assertEquals(
array('TD', 'TZ', 'TC', 'TB', 'TA', 'CTBar'),
@@ -59,7 +63,7 @@ class ClassCollectionLoaderTest extends \PHPUnit_Framework_TestCase
$m = $r->getMethod('getOrderedClasses');
$m->setAccessible(true);
$ordered = $m->invoke('Symfony\Component\ClassLoader\ClassCollectionLoader', $classes);
$ordered = $m->invoke(null, $classes);
$this->assertEquals($expected, array_map(function ($class) { return $class->getName(); }, $ordered));
}
@@ -91,6 +95,7 @@ class ClassCollectionLoaderTest extends \PHPUnit_Framework_TestCase
/**
* @dataProvider getDifferentOrdersForTraits
* @requires PHP 5.4
*/
public function testClassWithTraitsReordering(array $classes)
{
@@ -116,7 +121,7 @@ class ClassCollectionLoaderTest extends \PHPUnit_Framework_TestCase
$m = $r->getMethod('getOrderedClasses');
$m->setAccessible(true);
$ordered = $m->invoke('Symfony\Component\ClassLoader\ClassCollectionLoader', $classes);
$ordered = $m->invoke(null, $classes);
$this->assertEquals($expected, array_map(function ($class) { return $class->getName(); }, $ordered));
}
@@ -134,6 +139,9 @@ class ClassCollectionLoaderTest extends \PHPUnit_Framework_TestCase
);
}
/**
* @requires PHP 5.4
*/
public function testFixClassWithTraitsOrdering()
{
require_once __DIR__.'/Fixtures/ClassesWithParents/CTrait.php';
@@ -155,7 +163,7 @@ class ClassCollectionLoaderTest extends \PHPUnit_Framework_TestCase
$m = $r->getMethod('getOrderedClasses');
$m->setAccessible(true);
$ordered = $m->invoke('Symfony\Component\ClassLoader\ClassCollectionLoader', $classes);
$ordered = $m->invoke(null, $classes);
$this->assertEquals($expected, array_map(function ($class) { return $class->getName(); }, $ordered));
}
@@ -216,18 +224,20 @@ class ClassCollectionLoaderTest extends \PHPUnit_Framework_TestCase
public function testCommentStripping()
{
if (is_file($file = sys_get_temp_dir().'/bar.php')) {
if (is_file($file = __DIR__.'/bar.php')) {
unlink($file);
}
spl_autoload_register($r = function ($class) {
if (0 === strpos($class, 'Namespaced') || 0 === strpos($class, 'Pearlike_')) {
require_once __DIR__.'/Fixtures/'.str_replace(array('\\', '_'), '/', $class).'.php';
@require_once __DIR__.'/Fixtures/'.str_replace(array('\\', '_'), '/', $class).'.php';
}
});
$strictTypes = defined('HHVM_VERSION') ? '' : "\nnamespace {require __DIR__.'/Fixtures/Namespaced/WithStrictTypes.php';}";
ClassCollectionLoader::load(
array('Namespaced\\WithComments', 'Pearlike_WithComments'),
sys_get_temp_dir(),
array('Namespaced\\WithComments', 'Pearlike_WithComments', 'Namespaced\\WithDirMagic', 'Namespaced\\WithFileMagic', 'Namespaced\\WithHaltCompiler', $strictTypes ? 'Namespaced\\WithStrictTypes' : 'Namespaced\\WithComments'),
__DIR__,
'bar',
false
);
@@ -266,8 +276,13 @@ class Pearlike_WithComments
public static $loaded = true;
}
}
namespace {require __DIR__.'/Fixtures/Namespaced/WithDirMagic.php';}
namespace {require __DIR__.'/Fixtures/Namespaced/WithFileMagic.php';}
namespace {require __DIR__.'/Fixtures/Namespaced/WithHaltCompiler.php';}
EOF
, str_replace("<?php \n", '', file_get_contents($file)));
.$strictTypes,
str_replace(array("<?php \n", '\\\\'), array('', '/'), file_get_contents($file))
);
unlink($file);
}

View File

@@ -11,9 +11,10 @@
namespace Symfony\Component\ClassLoader\Tests;
use PHPUnit\Framework\TestCase;
use Symfony\Component\ClassLoader\ClassLoader;
class ClassLoaderTest extends \PHPUnit_Framework_TestCase
class ClassLoaderTest extends TestCase
{
public function testGetPrefixes()
{

View File

@@ -11,9 +11,10 @@
namespace Symfony\Component\ClassLoader\Tests;
use PHPUnit\Framework\TestCase;
use Symfony\Component\ClassLoader\ClassMapGenerator;
class ClassMapGeneratorTest extends \PHPUnit_Framework_TestCase
class ClassMapGeneratorTest extends TestCase
{
/**
* @var string|null
@@ -76,8 +77,11 @@ class ClassMapGeneratorTest extends \PHPUnit_Framework_TestCase
'Namespaced\\Foo' => realpath(__DIR__).'/Fixtures/Namespaced/Foo.php',
'Namespaced\\Baz' => realpath(__DIR__).'/Fixtures/Namespaced/Baz.php',
'Namespaced\\WithComments' => realpath(__DIR__).'/Fixtures/Namespaced/WithComments.php',
),
),
'Namespaced\\WithStrictTypes' => realpath(__DIR__).'/Fixtures/Namespaced/WithStrictTypes.php',
'Namespaced\\WithHaltCompiler' => realpath(__DIR__).'/Fixtures/Namespaced/WithHaltCompiler.php',
'Namespaced\\WithDirMagic' => realpath(__DIR__).'/Fixtures/Namespaced/WithDirMagic.php',
'Namespaced\\WithFileMagic' => realpath(__DIR__).'/Fixtures/Namespaced/WithFileMagic.php',
)),
array(__DIR__.'/Fixtures/beta/NamespaceCollision', array(
'NamespaceCollision\\A\\B\\Bar' => realpath(__DIR__).'/Fixtures/beta/NamespaceCollision/A/B/Bar.php',
'NamespaceCollision\\A\\B\\Foo' => realpath(__DIR__).'/Fixtures/beta/NamespaceCollision/A/B/Foo.php',
@@ -102,18 +106,24 @@ class ClassMapGeneratorTest extends \PHPUnit_Framework_TestCase
'ClassMap\\SomeParent' => realpath(__DIR__).'/Fixtures/classmap/SomeParent.php',
'ClassMap\\SomeClass' => realpath(__DIR__).'/Fixtures/classmap/SomeClass.php',
)),
array(__DIR__.'/Fixtures/php5.4', array(
);
if (\PHP_VERSION_ID >= 50400) {
$data[] = array(__DIR__.'/Fixtures/php5.4', array(
'TFoo' => __DIR__.'/Fixtures/php5.4/traits.php',
'CFoo' => __DIR__.'/Fixtures/php5.4/traits.php',
'Foo\\TBar' => __DIR__.'/Fixtures/php5.4/traits.php',
'Foo\\IBar' => __DIR__.'/Fixtures/php5.4/traits.php',
'Foo\\TFooBar' => __DIR__.'/Fixtures/php5.4/traits.php',
'Foo\\CBar' => __DIR__.'/Fixtures/php5.4/traits.php',
)),
array(__DIR__.'/Fixtures/php5.5', array(
));
}
if (\PHP_VERSION_ID >= 50500) {
$data[] = array(__DIR__.'/Fixtures/php5.5', array(
'ClassCons\\Foo' => __DIR__.'/Fixtures/php5.5/class_cons.php',
)),
);
));
}
return $data;
}

View File

@@ -0,0 +1,17 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace LegacyApc\Namespaced;
class Bar
{
public static $loaded = true;
}

View File

@@ -0,0 +1,17 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace LegacyApc\Namespaced;
class Baz
{
public static $loaded = true;
}

View File

@@ -0,0 +1,17 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace LegacyApc\Namespaced;
class Foo
{
public static $loaded = true;
}

View File

@@ -0,0 +1,17 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace LegacyApc\Namespaced;
class FooBar
{
public static $loaded = true;
}

View File

@@ -0,0 +1,6 @@
<?php
class LegacyApc_Pearlike_Bar
{
public static $loaded = true;
}

View File

@@ -0,0 +1,6 @@
<?php
class LegacyApc_Pearlike_Baz
{
public static $loaded = true;
}

View File

@@ -0,0 +1,6 @@
<?php
class LegacyApc_Pearlike_Foo
{
public static $loaded = true;
}

View File

@@ -0,0 +1,6 @@
<?php
class LegacyApcPrefixCollision_A_Bar
{
public static $loaded = true;
}

View File

@@ -0,0 +1,6 @@
<?php
class LegacyApcPrefixCollision_A_Foo
{
public static $loaded = true;
}

View File

@@ -0,0 +1,17 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace LegacyApc\NamespaceCollision\A;
class Bar
{
public static $loaded = true;
}

View File

@@ -0,0 +1,17 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace LegacyApc\NamespaceCollision\A;
class Foo
{
public static $loaded = true;
}

View File

@@ -0,0 +1,6 @@
<?php
class LegacyApcPrefixCollision_A_B_Bar
{
public static $loaded = true;
}

View File

@@ -0,0 +1,6 @@
<?php
class LegacyApcPrefixCollision_A_B_Foo
{
public static $loaded = true;
}

View File

@@ -0,0 +1,17 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace LegacyApc\NamespaceCollision\A\B;
class Bar
{
public static $loaded = true;
}

View File

@@ -0,0 +1,17 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace LegacyApc\NamespaceCollision\A\B;
class Foo
{
public static $loaded = true;
}

View File

@@ -0,0 +1,6 @@
<?php
class LegacyApc_Pearlike_FooBar
{
public static $loaded = true;
}

View File

@@ -0,0 +1,17 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace LegacyApc\Namespaced;
class FooBar
{
public static $loaded = true;
}

View File

@@ -0,0 +1,15 @@
<?php
/*
* foo
*/
namespace Namespaced;
class WithDirMagic
{
public function getDir()
{
return __DIR__;
}
}

View File

@@ -0,0 +1,15 @@
<?php
/*
* foo
*/
namespace Namespaced;
class WithFileMagic
{
public function getFile()
{
return __FILE__;
}
}

View File

@@ -0,0 +1,18 @@
<?php
/*
* foo
*/
namespace Namespaced;
class WithHaltCompiler
{
}
// the end of the script execution
__halt_compiler(); data
data
data
data
...

View File

@@ -0,0 +1,13 @@
<?php
/*
* foo
*/
declare(strict_types=1);
namespace Namespaced;
class WithStrictTypes
{
}

View File

@@ -0,0 +1,190 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\ClassLoader\Tests;
use PHPUnit\Framework\TestCase;
use Symfony\Component\ClassLoader\ApcUniversalClassLoader;
/**
* @group legacy
*/
class LegacyApcUniversalClassLoaderTest extends TestCase
{
protected function setUp()
{
if (ini_get('apc.enabled') && ini_get('apc.enable_cli')) {
apcu_clear_cache();
} else {
$this->markTestSkipped('APC is not enabled.');
}
}
protected function tearDown()
{
if (ini_get('apc.enabled') && ini_get('apc.enable_cli')) {
apcu_clear_cache();
}
}
public function testConstructor()
{
$loader = new ApcUniversalClassLoader('test.prefix.');
$loader->registerNamespace('LegacyApc\Namespaced', __DIR__.DIRECTORY_SEPARATOR.'Fixtures');
$this->assertEquals($loader->findFile('\LegacyApc\Namespaced\FooBar'), apcu_fetch('test.prefix.\LegacyApc\Namespaced\FooBar'), '__construct() takes a prefix as its first argument');
}
/**
* @dataProvider getLoadClassTests
*/
public function testLoadClass($className, $testClassName, $message)
{
$loader = new ApcUniversalClassLoader('test.prefix.');
$loader->registerNamespace('LegacyApc\Namespaced', __DIR__.DIRECTORY_SEPARATOR.'Fixtures');
$loader->registerPrefix('LegacyApc_Pearlike_', __DIR__.DIRECTORY_SEPARATOR.'Fixtures');
$loader->loadClass($testClassName);
$this->assertTrue(class_exists($className), $message);
}
public function getLoadClassTests()
{
return array(
array('\\LegacyApc\\Namespaced\\Foo', 'LegacyApc\\Namespaced\\Foo', '->loadClass() loads LegacyApc\Namespaced\Foo class'),
array('LegacyApc_Pearlike_Foo', 'LegacyApc_Pearlike_Foo', '->loadClass() loads LegacyApc_Pearlike_Foo class'),
);
}
/**
* @dataProvider getLoadClassFromFallbackTests
*/
public function testLoadClassFromFallback($className, $testClassName, $message)
{
$loader = new ApcUniversalClassLoader('test.prefix.fallback');
$loader->registerNamespace('LegacyApc\Namespaced', __DIR__.DIRECTORY_SEPARATOR.'Fixtures');
$loader->registerPrefix('LegacyApc_Pearlike_', __DIR__.DIRECTORY_SEPARATOR.'Fixtures');
$loader->registerNamespaceFallbacks(array(__DIR__.DIRECTORY_SEPARATOR.'Fixtures/LegacyApc/fallback'));
$loader->registerPrefixFallbacks(array(__DIR__.DIRECTORY_SEPARATOR.'Fixtures/LegacyApc/fallback'));
$loader->loadClass($testClassName);
$this->assertTrue(class_exists($className), $message);
}
public function getLoadClassFromFallbackTests()
{
return array(
array('\\LegacyApc\\Namespaced\\Baz', 'LegacyApc\\Namespaced\\Baz', '->loadClass() loads LegacyApc\Namespaced\Baz class'),
array('LegacyApc_Pearlike_Baz', 'LegacyApc_Pearlike_Baz', '->loadClass() loads LegacyApc_Pearlike_Baz class'),
array('\\LegacyApc\\Namespaced\\FooBar', 'LegacyApc\\Namespaced\\FooBar', '->loadClass() loads LegacyApc\Namespaced\Baz class from fallback dir'),
array('LegacyApc_Pearlike_FooBar', 'LegacyApc_Pearlike_FooBar', '->loadClass() loads LegacyApc_Pearlike_Baz class from fallback dir'),
);
}
/**
* @dataProvider getLoadClassNamespaceCollisionTests
*/
public function testLoadClassNamespaceCollision($namespaces, $className, $message)
{
$loader = new ApcUniversalClassLoader('test.prefix.collision.');
$loader->registerNamespaces($namespaces);
$loader->loadClass($className);
$this->assertTrue(class_exists($className), $message);
}
public function getLoadClassNamespaceCollisionTests()
{
return array(
array(
array(
'LegacyApc\\NamespaceCollision\\A' => __DIR__.DIRECTORY_SEPARATOR.'Fixtures/LegacyApc/alpha',
'LegacyApc\\NamespaceCollision\\A\\B' => __DIR__.DIRECTORY_SEPARATOR.'Fixtures/LegacyApc/beta',
),
'LegacyApc\NamespaceCollision\A\Foo',
'->loadClass() loads NamespaceCollision\A\Foo from alpha.',
),
array(
array(
'LegacyApc\\NamespaceCollision\\A\\B' => __DIR__.DIRECTORY_SEPARATOR.'Fixtures/LegacyApc/beta',
'LegacyApc\\NamespaceCollision\\A' => __DIR__.DIRECTORY_SEPARATOR.'Fixtures/LegacyApc/alpha',
),
'LegacyApc\NamespaceCollision\A\Bar',
'->loadClass() loads NamespaceCollision\A\Bar from alpha.',
),
array(
array(
'LegacyApc\\NamespaceCollision\\A' => __DIR__.DIRECTORY_SEPARATOR.'Fixtures/LegacyApc/alpha',
'LegacyApc\\NamespaceCollision\\A\\B' => __DIR__.DIRECTORY_SEPARATOR.'Fixtures/LegacyApc/beta',
),
'LegacyApc\NamespaceCollision\A\B\Foo',
'->loadClass() loads NamespaceCollision\A\B\Foo from beta.',
),
array(
array(
'LegacyApc\\NamespaceCollision\\A\\B' => __DIR__.DIRECTORY_SEPARATOR.'Fixtures/LegacyApc/beta',
'LegacyApc\\NamespaceCollision\\A' => __DIR__.DIRECTORY_SEPARATOR.'Fixtures/LegacyApc/alpha',
),
'LegacyApc\NamespaceCollision\A\B\Bar',
'->loadClass() loads NamespaceCollision\A\B\Bar from beta.',
),
);
}
/**
* @dataProvider getLoadClassPrefixCollisionTests
*/
public function testLoadClassPrefixCollision($prefixes, $className, $message)
{
$loader = new ApcUniversalClassLoader('test.prefix.collision.');
$loader->registerPrefixes($prefixes);
$loader->loadClass($className);
$this->assertTrue(class_exists($className), $message);
}
public function getLoadClassPrefixCollisionTests()
{
return array(
array(
array(
'LegacyApcPrefixCollision_A_' => __DIR__.DIRECTORY_SEPARATOR.'Fixtures/LegacyApc/alpha/LegacyApc',
'LegacyApcPrefixCollision_A_B_' => __DIR__.DIRECTORY_SEPARATOR.'Fixtures/LegacyApc/beta/LegacyApc',
),
'LegacyApcPrefixCollision_A_Foo',
'->loadClass() loads LegacyApcPrefixCollision_A_Foo from alpha.',
),
array(
array(
'LegacyApcPrefixCollision_A_B_' => __DIR__.DIRECTORY_SEPARATOR.'Fixtures/LegacyApc/beta/LegacyApc',
'LegacyApcPrefixCollision_A_' => __DIR__.DIRECTORY_SEPARATOR.'Fixtures/LegacyApc/alpha/LegacyApc',
),
'LegacyApcPrefixCollision_A_Bar',
'->loadClass() loads LegacyApcPrefixCollision_A_Bar from alpha.',
),
array(
array(
'LegacyApcPrefixCollision_A_' => __DIR__.DIRECTORY_SEPARATOR.'Fixtures/LegacyApc/alpha/LegacyApc',
'LegacyApcPrefixCollision_A_B_' => __DIR__.DIRECTORY_SEPARATOR.'Fixtures/LegacyApc/beta/LegacyApc',
),
'LegacyApcPrefixCollision_A_B_Foo',
'->loadClass() loads LegacyApcPrefixCollision_A_B_Foo from beta.',
),
array(
array(
'LegacyApcPrefixCollision_A_B_' => __DIR__.DIRECTORY_SEPARATOR.'Fixtures/LegacyApc/beta/LegacyApc',
'LegacyApcPrefixCollision_A_' => __DIR__.DIRECTORY_SEPARATOR.'Fixtures/LegacyApc/alpha/LegacyApc',
),
'LegacyApcPrefixCollision_A_B_Bar',
'->loadClass() loads LegacyApcPrefixCollision_A_B_Bar from beta.',
),
);
}
}

View File

@@ -0,0 +1,224 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\ClassLoader\Tests;
use PHPUnit\Framework\TestCase;
use Symfony\Component\ClassLoader\UniversalClassLoader;
/**
* @group legacy
*/
class LegacyUniversalClassLoaderTest extends TestCase
{
/**
* @dataProvider getLoadClassTests
*/
public function testLoadClass($className, $testClassName, $message)
{
$loader = new UniversalClassLoader();
$loader->registerNamespace('Namespaced', __DIR__.DIRECTORY_SEPARATOR.'Fixtures');
$loader->registerPrefix('Pearlike_', __DIR__.DIRECTORY_SEPARATOR.'Fixtures');
$this->assertTrue($loader->loadClass($testClassName));
$this->assertTrue(class_exists($className), $message);
}
public function getLoadClassTests()
{
return array(
array('\\Namespaced\\Foo', 'Namespaced\\Foo', '->loadClass() loads Namespaced\Foo class'),
array('\\Pearlike_Foo', 'Pearlike_Foo', '->loadClass() loads Pearlike_Foo class'),
);
}
public function testUseIncludePath()
{
$loader = new UniversalClassLoader();
$this->assertFalse($loader->getUseIncludePath());
$this->assertNull($loader->findFile('Foo'));
$includePath = get_include_path();
$loader->useIncludePath(true);
$this->assertTrue($loader->getUseIncludePath());
set_include_path(__DIR__.'/Fixtures/includepath'.PATH_SEPARATOR.$includePath);
$this->assertEquals(__DIR__.DIRECTORY_SEPARATOR.'Fixtures'.DIRECTORY_SEPARATOR.'includepath'.DIRECTORY_SEPARATOR.'Foo.php', $loader->findFile('Foo'));
set_include_path($includePath);
}
public function testGetNamespaces()
{
$loader = new UniversalClassLoader();
$loader->registerNamespace('Foo', __DIR__.DIRECTORY_SEPARATOR.'Fixtures');
$loader->registerNamespace('Bar', __DIR__.DIRECTORY_SEPARATOR.'Fixtures');
$loader->registerNamespace('Bas', __DIR__.DIRECTORY_SEPARATOR.'Fixtures');
$namespaces = $loader->getNamespaces();
$this->assertArrayHasKey('Foo', $namespaces);
$this->assertArrayNotHasKey('Foo1', $namespaces);
$this->assertArrayHasKey('Bar', $namespaces);
$this->assertArrayHasKey('Bas', $namespaces);
}
public function testGetPrefixes()
{
$loader = new UniversalClassLoader();
$loader->registerPrefix('Foo', __DIR__.DIRECTORY_SEPARATOR.'Fixtures');
$loader->registerPrefix('Bar', __DIR__.DIRECTORY_SEPARATOR.'Fixtures');
$loader->registerPrefix('Bas', __DIR__.DIRECTORY_SEPARATOR.'Fixtures');
$prefixes = $loader->getPrefixes();
$this->assertArrayHasKey('Foo', $prefixes);
$this->assertArrayNotHasKey('Foo1', $prefixes);
$this->assertArrayHasKey('Bar', $prefixes);
$this->assertArrayHasKey('Bas', $prefixes);
}
/**
* @dataProvider getLoadClassFromFallbackTests
*/
public function testLoadClassFromFallback($className, $testClassName, $message)
{
$loader = new UniversalClassLoader();
$loader->registerNamespace('Namespaced', __DIR__.DIRECTORY_SEPARATOR.'Fixtures');
$loader->registerPrefix('Pearlike_', __DIR__.DIRECTORY_SEPARATOR.'Fixtures');
$loader->registerNamespaceFallbacks(array(__DIR__.DIRECTORY_SEPARATOR.'Fixtures/fallback'));
$loader->registerPrefixFallbacks(array(__DIR__.DIRECTORY_SEPARATOR.'Fixtures/fallback'));
$this->assertTrue($loader->loadClass($testClassName));
$this->assertTrue(class_exists($className), $message);
}
public function getLoadClassFromFallbackTests()
{
return array(
array('\\Namespaced\\Baz', 'Namespaced\\Baz', '->loadClass() loads Namespaced\Baz class'),
array('\\Pearlike_Baz', 'Pearlike_Baz', '->loadClass() loads Pearlike_Baz class'),
array('\\Namespaced\\FooBar', 'Namespaced\\FooBar', '->loadClass() loads Namespaced\Baz class from fallback dir'),
array('\\Pearlike_FooBar', 'Pearlike_FooBar', '->loadClass() loads Pearlike_Baz class from fallback dir'),
);
}
public function testRegisterPrefixFallback()
{
$loader = new UniversalClassLoader();
$loader->registerPrefixFallback(__DIR__.DIRECTORY_SEPARATOR.'Fixtures/fallback');
$this->assertEquals(array(__DIR__.DIRECTORY_SEPARATOR.'Fixtures/fallback'), $loader->getPrefixFallbacks());
}
public function testRegisterNamespaceFallback()
{
$loader = new UniversalClassLoader();
$loader->registerNamespaceFallback(__DIR__.DIRECTORY_SEPARATOR.'Fixtures/Namespaced/fallback');
$this->assertEquals(array(__DIR__.DIRECTORY_SEPARATOR.'Fixtures/Namespaced/fallback'), $loader->getNamespaceFallbacks());
}
/**
* @dataProvider getLoadClassNamespaceCollisionTests
*/
public function testLoadClassNamespaceCollision($namespaces, $className, $message)
{
$loader = new UniversalClassLoader();
$loader->registerNamespaces($namespaces);
$this->assertTrue($loader->loadClass($className));
$this->assertTrue(class_exists($className), $message);
}
public function getLoadClassNamespaceCollisionTests()
{
return array(
array(
array(
'NamespaceCollision\\A' => __DIR__.DIRECTORY_SEPARATOR.'Fixtures/alpha',
'NamespaceCollision\\A\\B' => __DIR__.DIRECTORY_SEPARATOR.'Fixtures/beta',
),
'NamespaceCollision\A\Foo',
'->loadClass() loads NamespaceCollision\A\Foo from alpha.',
),
array(
array(
'NamespaceCollision\\A\\B' => __DIR__.DIRECTORY_SEPARATOR.'Fixtures/beta',
'NamespaceCollision\\A' => __DIR__.DIRECTORY_SEPARATOR.'Fixtures/alpha',
),
'NamespaceCollision\A\Bar',
'->loadClass() loads NamespaceCollision\A\Bar from alpha.',
),
array(
array(
'NamespaceCollision\\A' => __DIR__.DIRECTORY_SEPARATOR.'Fixtures/alpha',
'NamespaceCollision\\A\\B' => __DIR__.DIRECTORY_SEPARATOR.'Fixtures/beta',
),
'NamespaceCollision\A\B\Foo',
'->loadClass() loads NamespaceCollision\A\B\Foo from beta.',
),
array(
array(
'NamespaceCollision\\A\\B' => __DIR__.DIRECTORY_SEPARATOR.'Fixtures/beta',
'NamespaceCollision\\A' => __DIR__.DIRECTORY_SEPARATOR.'Fixtures/alpha',
),
'NamespaceCollision\A\B\Bar',
'->loadClass() loads NamespaceCollision\A\B\Bar from beta.',
),
);
}
/**
* @dataProvider getLoadClassPrefixCollisionTests
*/
public function testLoadClassPrefixCollision($prefixes, $className, $message)
{
$loader = new UniversalClassLoader();
$loader->registerPrefixes($prefixes);
$this->assertTrue($loader->loadClass($className));
$this->assertTrue(class_exists($className), $message);
}
public function getLoadClassPrefixCollisionTests()
{
return array(
array(
array(
'PrefixCollision_A_' => __DIR__.DIRECTORY_SEPARATOR.'Fixtures/alpha',
'PrefixCollision_A_B_' => __DIR__.DIRECTORY_SEPARATOR.'Fixtures/beta',
),
'PrefixCollision_A_Foo',
'->loadClass() loads PrefixCollision_A_Foo from alpha.',
),
array(
array(
'PrefixCollision_A_B_' => __DIR__.DIRECTORY_SEPARATOR.'Fixtures/beta',
'PrefixCollision_A_' => __DIR__.DIRECTORY_SEPARATOR.'Fixtures/alpha',
),
'PrefixCollision_A_Bar',
'->loadClass() loads PrefixCollision_A_Bar from alpha.',
),
array(
array(
'PrefixCollision_A_' => __DIR__.DIRECTORY_SEPARATOR.'Fixtures/alpha',
'PrefixCollision_A_B_' => __DIR__.DIRECTORY_SEPARATOR.'Fixtures/beta',
),
'PrefixCollision_A_B_Foo',
'->loadClass() loads PrefixCollision_A_B_Foo from beta.',
),
array(
array(
'PrefixCollision_A_B_' => __DIR__.DIRECTORY_SEPARATOR.'Fixtures/beta',
'PrefixCollision_A_' => __DIR__.DIRECTORY_SEPARATOR.'Fixtures/alpha',
),
'PrefixCollision_A_B_Bar',
'->loadClass() loads PrefixCollision_A_B_Bar from beta.',
),
);
}
}

View File

@@ -11,9 +11,10 @@
namespace Symfony\Component\ClassLoader\Tests;
use PHPUnit\Framework\TestCase;
use Symfony\Component\ClassLoader\Psr4ClassLoader;
class Psr4ClassLoaderTest extends \PHPUnit_Framework_TestCase
class Psr4ClassLoaderTest extends TestCase
{
/**
* @param string $className

307
UniversalClassLoader.php Normal file
View File

@@ -0,0 +1,307 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Component\ClassLoader;
@trigger_error('The '.__NAMESPACE__.'\UniversalClassLoader class is deprecated since version 2.7 and will be removed in 3.0. Use the Symfony\Component\ClassLoader\ClassLoader class instead.', E_USER_DEPRECATED);
/**
* UniversalClassLoader implements a "universal" autoloader for PHP 5.3.
*
* It is able to load classes that use either:
*
* * The technical interoperability standards for PHP 5.3 namespaces and
* class names (https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md);
*
* * The PEAR naming convention for classes (http://pear.php.net/).
*
* Classes from a sub-namespace or a sub-hierarchy of PEAR classes can be
* looked for in a list of locations to ease the vendoring of a sub-set of
* classes for large projects.
*
* Example usage:
*
* $loader = new UniversalClassLoader();
*
* // register classes with namespaces
* $loader->registerNamespaces(array(
* 'Symfony\Component' => __DIR__.'/component',
* 'Symfony' => __DIR__.'/framework',
* 'Sensio' => array(__DIR__.'/src', __DIR__.'/vendor'),
* ));
*
* // register a library using the PEAR naming convention
* $loader->registerPrefixes(array(
* 'Swift_' => __DIR__.'/Swift',
* ));
*
*
* // to enable searching the include path (e.g. for PEAR packages)
* $loader->useIncludePath(true);
*
* // activate the autoloader
* $loader->register();
*
* In this example, if you try to use a class in the Symfony\Component
* namespace or one of its children (Symfony\Component\Console for instance),
* the autoloader will first look for the class under the component/
* directory, and it will then fallback to the framework/ directory if not
* found before giving up.
*
* @author Fabien Potencier <fabien@symfony.com>
*
* @deprecated since version 2.4, to be removed in 3.0.
* Use the {@link ClassLoader} class instead.
*/
class UniversalClassLoader
{
private $namespaces = array();
private $prefixes = array();
private $namespaceFallbacks = array();
private $prefixFallbacks = array();
private $useIncludePath = false;
/**
* Turns on searching the include for class files. Allows easy loading
* of installed PEAR packages.
*
* @param bool $useIncludePath
*/
public function useIncludePath($useIncludePath)
{
$this->useIncludePath = (bool) $useIncludePath;
}
/**
* Can be used to check if the autoloader uses the include path to check
* for classes.
*
* @return bool
*/
public function getUseIncludePath()
{
return $this->useIncludePath;
}
/**
* Gets the configured namespaces.
*
* @return array A hash with namespaces as keys and directories as values
*/
public function getNamespaces()
{
return $this->namespaces;
}
/**
* Gets the configured class prefixes.
*
* @return array A hash with class prefixes as keys and directories as values
*/
public function getPrefixes()
{
return $this->prefixes;
}
/**
* Gets the directory(ies) to use as a fallback for namespaces.
*
* @return array An array of directories
*/
public function getNamespaceFallbacks()
{
return $this->namespaceFallbacks;
}
/**
* Gets the directory(ies) to use as a fallback for class prefixes.
*
* @return array An array of directories
*/
public function getPrefixFallbacks()
{
return $this->prefixFallbacks;
}
/**
* Registers the directory to use as a fallback for namespaces.
*
* @param array $dirs An array of directories
*/
public function registerNamespaceFallbacks(array $dirs)
{
$this->namespaceFallbacks = $dirs;
}
/**
* Registers a directory to use as a fallback for namespaces.
*
* @param string $dir A directory
*/
public function registerNamespaceFallback($dir)
{
$this->namespaceFallbacks[] = $dir;
}
/**
* Registers directories to use as a fallback for class prefixes.
*
* @param array $dirs An array of directories
*/
public function registerPrefixFallbacks(array $dirs)
{
$this->prefixFallbacks = $dirs;
}
/**
* Registers a directory to use as a fallback for class prefixes.
*
* @param string $dir A directory
*/
public function registerPrefixFallback($dir)
{
$this->prefixFallbacks[] = $dir;
}
/**
* Registers an array of namespaces.
*
* @param array $namespaces An array of namespaces (namespaces as keys and locations as values)
*/
public function registerNamespaces(array $namespaces)
{
foreach ($namespaces as $namespace => $locations) {
$this->namespaces[$namespace] = (array) $locations;
}
}
/**
* Registers a namespace.
*
* @param string $namespace The namespace
* @param array|string $paths The location(s) of the namespace
*/
public function registerNamespace($namespace, $paths)
{
$this->namespaces[$namespace] = (array) $paths;
}
/**
* Registers an array of classes using the PEAR naming convention.
*
* @param array $classes An array of classes (prefixes as keys and locations as values)
*/
public function registerPrefixes(array $classes)
{
foreach ($classes as $prefix => $locations) {
$this->prefixes[$prefix] = (array) $locations;
}
}
/**
* Registers a set of classes using the PEAR naming convention.
*
* @param string $prefix The classes prefix
* @param array|string $paths The location(s) of the classes
*/
public function registerPrefix($prefix, $paths)
{
$this->prefixes[$prefix] = (array) $paths;
}
/**
* Registers this instance as an autoloader.
*
* @param bool $prepend Whether to prepend the autoloader or not
*/
public function register($prepend = false)
{
spl_autoload_register(array($this, 'loadClass'), true, $prepend);
}
/**
* Loads the given class or interface.
*
* @param string $class The name of the class
*
* @return bool|null True, if loaded
*/
public function loadClass($class)
{
if ($file = $this->findFile($class)) {
require $file;
return true;
}
}
/**
* Finds the path to the file where the class is defined.
*
* @param string $class The name of the class
*
* @return string|null The path, if found
*/
public function findFile($class)
{
if (false !== $pos = strrpos($class, '\\')) {
// namespaced class name
$namespace = substr($class, 0, $pos);
$className = substr($class, $pos + 1);
$normalizedClass = str_replace('\\', DIRECTORY_SEPARATOR, $namespace).DIRECTORY_SEPARATOR.str_replace('_', DIRECTORY_SEPARATOR, $className).'.php';
foreach ($this->namespaces as $ns => $dirs) {
if (0 !== strpos($namespace, $ns)) {
continue;
}
foreach ($dirs as $dir) {
$file = $dir.DIRECTORY_SEPARATOR.$normalizedClass;
if (is_file($file)) {
return $file;
}
}
}
foreach ($this->namespaceFallbacks as $dir) {
$file = $dir.DIRECTORY_SEPARATOR.$normalizedClass;
if (is_file($file)) {
return $file;
}
}
} else {
// PEAR-like class name
$normalizedClass = str_replace('_', DIRECTORY_SEPARATOR, $class).'.php';
foreach ($this->prefixes as $prefix => $dirs) {
if (0 !== strpos($class, $prefix)) {
continue;
}
foreach ($dirs as $dir) {
$file = $dir.DIRECTORY_SEPARATOR.$normalizedClass;
if (is_file($file)) {
return $file;
}
}
}
foreach ($this->prefixFallbacks as $dir) {
$file = $dir.DIRECTORY_SEPARATOR.$normalizedClass;
if (is_file($file)) {
return $file;
}
}
}
if ($this->useIncludePath && $file = stream_resolve_include_path($normalizedClass)) {
return $file;
}
}
}

View File

@@ -16,10 +16,12 @@ namespace Symfony\Component\ClassLoader;
*
* It expects an object implementing a findFile method to find the file. This
* allow using it as a wrapper around the other loaders of the component (the
* ClassLoader for instance) but also around any other autoloaders following
* this convention (the Composer one for instance).
* ClassLoader and the UniversalClassLoader for instance) but also around any
* other autoloaders following this convention (the Composer one for instance).
*
* // with a Symfony autoloader
* use Symfony\Component\ClassLoader\ClassLoader;
*
* $loader = new ClassLoader();
* $loader->addPrefix('Symfony\Component', __DIR__.'/component');
* $loader->addPrefix('Symfony', __DIR__.'/framework');

View File

@@ -16,10 +16,12 @@ namespace Symfony\Component\ClassLoader;
*
* It expects an object implementing a findFile method to find the file. This
* allows using it as a wrapper around the other loaders of the component (the
* ClassLoader for instance) but also around any other autoloaders following
* this convention (the Composer one for instance).
* ClassLoader and the UniversalClassLoader for instance) but also around any
* other autoloaders following this convention (the Composer one for instance).
*
* // with a Symfony autoloader
* use Symfony\Component\ClassLoader\ClassLoader;
*
* $loader = new ClassLoader();
* $loader->addPrefix('Symfony\Component', __DIR__.'/component');
* $loader->addPrefix('Symfony', __DIR__.'/framework');

View File

@@ -17,14 +17,11 @@
],
"minimum-stability": "dev",
"require": {
"php": ">=5.5.9"
},
"require-dev": {
"symfony/finder": "~2.8|~3.0",
"php": ">=5.3.9",
"symfony/polyfill-apcu": "~1.1"
},
"suggest": {
"symfony/polyfill-apcu": "For using ApcClassLoader on HHVM"
"require-dev": {
"symfony/finder": "^2.0.5"
},
"autoload": {
"psr-4": { "Symfony\\Component\\ClassLoader\\": "" },
@@ -34,7 +31,7 @@
},
"extra": {
"branch-alias": {
"dev-master": "3.0-dev"
"dev-master": "2.7-dev"
}
}
}

View File

@@ -5,6 +5,8 @@
backupGlobals="false"
colors="true"
bootstrap="vendor/autoload.php"
failOnRisky="true"
failOnWarning="true"
>
<php>
<ini name="error_reporting" value="-1" />