Compare commits

..

30 Commits
v3.0.3 ... 2.7

Author SHA1 Message Date
Fabien Potencier
78710673c0 fixed years in copyright 2018-01-03 08:23:28 +01:00
Kévin Dunglas
9dac4c57cf Update LICENSE year... forever 2017-12-31 13:13:41 +01:00
Fabien Potencier
59ab31e13c fixed some deprecation messages 2017-12-31 05:55:05 +01:00
Nicolas Grekas
eb2590d94c Remove useless docblocks 2017-10-29 10:49:53 +01:00
Nicolas Grekas
5d77753a96 [DI] minor docblock fixes 2017-10-24 13:40:19 +02:00
Fabien Potencier
f4278d53d1 minor #24342 removed useless PHPDoc (OskarStark)
This PR was squashed before being merged into the 2.7 branch (closes #24342).

Discussion
----------

removed useless PHPDoc

| Q             | A
| ------------- | ---
| Branch?       | 2.7
| Bug fix?      | no
| New feature?  | no <!-- don't forget updating src/**/CHANGELOG.md files -->
| BC breaks?    | no
| Deprecations? | no <!-- don't forget updating UPGRADE-*.md files -->
| Tests pass?   | yes
| Fixed tickets |
| License       | MIT
| Doc PR        | n/a

Commits
-------

5ee9043d8b removed useless PHPDoc
2017-09-30 07:00:25 -07:00
Oskar Stark
9ae87e8c34 removed useless PHPDoc 2017-09-30 07:00:23 -07:00
SpacePossum
f8843095b2 [CS][2.7] yoda_style, no_unneeded_curly_braces, no_unneeded_final_method, semicolon_after_instruction 2017-09-15 11:46:57 +02:00
Dariusz
2c4235602f Fix indent of methods 2017-07-04 23:00:55 +02:00
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
Nicolas Grekas
bec3ae4363 [ClassLoader] Fix declared classes being computed when not needed 2016-07-06 10:59:52 +02:00
Fabien Potencier
f94075a8ab removed dots at the end of @param and @return 2016-06-28 08:24:06 +02:00
Fabien Potencier
7e758508e0 Merge branch '2.3' into 2.7
* 2.3:
  [ci] Get ICU/intl from github instead of nebm.ist.utl.pt/~glopes
  [Debug] Fix handling of php7 throwables
  [Process] remove dead code
  [ClassLoader] Fix storing not-found classes in APC cache
  [Form] cs fixes in date types
2016-03-30 12:21:35 +02:00
Nicolas Grekas
0a01933a8d [ClassLoader] Fix storing not-found classes in APC cache 2016-03-28 10:34:42 +02:00
Nicolas Grekas
f5df9e4df1 Merge branch '2.3' into 2.7
* 2.3:
  [ci] use hirak/prestissimo
  [Filesystem] Fix transient tests
  [HttpFoundation] Avoid warnings when checking malicious IPs
  [HttpFoundation] Set the Content-Range header if the requested Range is unsatisfied

Conflicts:
	appveyor.yml
	src/Symfony/Component/Filesystem/Tests/FilesystemTest.php
2016-03-10 20:23:56 +01:00
Nicolas Grekas
d77ac7df59 [Filesystem] Fix transient tests 2016-03-10 15:49:24 +01:00
Fabien Potencier
eb9cd31d2f Merge branch '2.3' into 2.7
* 2.3:
  Updated all the README files
  [TwigBundle] Fix failing test on appveyor
  [FrameworkBundle] Fix a regression in handling absolute and namespaced template paths
  Allow to normalize \Traversable
  Remove _path from query parameters when fragment is a subrequest and request attributes are already set Added tests for _path removal in FragmentListener
  Simplified everything
  Added a test
  Fixed the problem in an easier way
  Fixed a syntax issue
  Improved the error message when a template is not found
  [CodingStandards] Conformed to coding standards
  [TwigBundle] fixed Include file locations in "Template could not be found" exception
2016-03-04 08:52:28 +01:00
Javier Eguiluz
355a6b3ee2 Updated all the README files 2016-03-04 08:12:06 +01:00
Paráda József
283e453827 [2.7] Fix tests 2016-01-30 16:53:18 +01:00
44 changed files with 1445 additions and 181 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;
@@ -57,10 +57,8 @@ class ApcClassLoader
protected $decorated;
/**
* Constructor.
*
* @param string $prefix The APC namespace prefix to use.
* @param object $decorated A class loader object that implements the findFile() method.
* @param string $prefix The APC namespace prefix to use
* @param object $decorated A class loader object that implements the findFile() method
*
* @throws \RuntimeException
* @throws \InvalidArgumentException
@@ -122,8 +120,10 @@ class ApcClassLoader
*/
public function findFile($class)
{
if (false === $file = apcu_fetch($this->prefix.$class)) {
apcu_store($this->prefix.$class, $file = $this->decorated->findFile($class));
$file = apcu_fetch($this->prefix.$class, $success);
if (!$success) {
apcu_store($this->prefix.$class, $file = $this->decorated->findFile($class) ?: null);
}
return $file;

101
ApcUniversalClassLoader.php Normal file
View File

@@ -0,0 +1,101 @@
<?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 Symfony 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;
/**
* @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

@@ -43,9 +43,12 @@ class ClassCollectionLoader
self::$loaded[$name] = true;
$declared = array_merge(get_declared_classes(), get_declared_interfaces(), get_declared_traits());
if ($adaptive) {
$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
@@ -84,12 +92,29 @@ class ClassCollectionLoader
}
}
if (!$reload && is_file($cache)) {
if (!$reload && file_exists($cache)) {
require_once $cache;
return;
}
if (!$adaptive) {
$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) {
@@ -97,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) {
@@ -175,7 +215,7 @@ class ClassCollectionLoader
do {
$token = $tokens[++$i];
$output .= isset($token[1]) && 'b"' !== $token ? $token[1] : $token;
} while ($token[0] !== T_END_HEREDOC);
} while (T_END_HEREDOC !== $token[0]);
$output .= "\n";
$rawChunk = '';
} elseif (T_CONSTANT_ENCAPSED_STRING === $token[0]) {
@@ -192,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();
@@ -235,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());
@@ -248,8 +294,6 @@ class ClassCollectionLoader
/**
* Gets an ordered array of passed classes including all their dependencies.
*
* @param array $classes
*
* @return \ReflectionClass[] An array of sorted \ReflectionClass instances (dependencies added if needed)
*
* @throws \InvalidArgumentException When a class can't be loaded
@@ -289,10 +333,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,15 +64,15 @@ class ClassMapGenerator
continue;
}
$path = $file->getRealPath();
$path = $file->getRealPath() ?: $file->getPathname();
if (pathinfo($path, PATHINFO_EXTENSION) !== 'php') {
if ('php' !== pathinfo($path, PATHINFO_EXTENSION)) {
continue;
}
$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) {

118
DebugClassLoader.php Normal file
View File

@@ -0,0 +1,118 @@
<?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 Symfony 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;
/**
* @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 Symfony 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-2018 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

@@ -21,8 +21,6 @@ class MapClassLoader
private $map = array();
/**
* Constructor.
*
* @param array $map A map where keys are classes and values the absolute file path
*/
public function __construct(array $map)

View File

@@ -20,9 +20,6 @@ namespace Symfony\Component\ClassLoader;
*/
class Psr4ClassLoader
{
/**
* @var array
*/
private $prefixes = array();
/**
@@ -45,7 +42,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

@@ -1,85 +1,14 @@
ClassLoader Component
=====================
ClassLoader loads your project classes automatically if they follow some
standard PHP conventions.
The ClassLoader object is able to autoload classes that implement the PSR-0
standard or the PEAR naming convention.
First, register the autoloader:
```php
require_once __DIR__.'/src/Symfony/Component/ClassLoader/ClassLoader.php';
use Symfony\Component\ClassLoader\ClassLoader;
$loader = new ClassLoader();
$loader->register();
```
Then, register some namespaces with the `addPrefix()` method:
```php
$loader->addPrefix('Symfony', __DIR__.'/src');
$loader->addPrefix('Monolog', __DIR__.'/vendor/monolog/src');
```
The `addPrefix()` method takes a namespace prefix and a path where to look for
the classes as arguments.
You can also register a sub-namespaces:
```php
$loader->addPrefix('Doctrine\\Common', __DIR__.'/vendor/doctrine-common/lib');
```
The order of registration is significant and the first registered namespace
takes precedence over later registered one.
You can also register more than one path for a given namespace:
```php
$loader->addPrefix('Symfony', array(__DIR__.'/src', __DIR__.'/symfony/src'));
```
Alternatively, you can use the `addPrefixes()` method to register more
than one namespace at once:
```php
$loader->addPrefixes(array(
'Symfony' => array(__DIR__.'/src', __DIR__.'/symfony/src'),
'Doctrine\\Common' => __DIR__.'/vendor/doctrine-common/lib',
'Doctrine' => __DIR__.'/vendor/doctrine/lib',
'Monolog' => __DIR__.'/vendor/monolog/src',
));
```
For better performance, you can use the APC class loader:
```php
require_once __DIR__.'/src/Symfony/Component/ClassLoader/ClassLoader.php';
require_once __DIR__.'/src/Symfony/Component/ClassLoader/ApcClassLoader.php';
use Symfony\Component\ClassLoader\ClassLoader;
use Symfony\Component\ClassLoader\ApcClassLoader;
$loader = new ClassLoader();
$loader->addPrefix('Symfony', __DIR__.'/src');
$loader = new ApcClassLoader('apc.prefix.', $loader);
$loader->register();
```
Furthermore, the component provides tools to aggregate classes into a single
file, which is especially useful to improve performance on servers that do not
provide byte caches.
The ClassLoader component provides tools to autoload your classes and cache
their locations for performance.
Resources
---------
You can run the unit tests with the following command:
$ cd path/to/Symfony/Component/ClassLoader/
$ composer install
$ phpunit
* [Documentation](https://symfony.com/doc/current/components/class_loader/index.html)
* [Contributing](https://symfony.com/doc/current/contributing/index.html)
* [Report issues](https://github.com/symfony/symfony/issues) and
[send Pull Requests](https://github.com/symfony/symfony/pulls)
in the [main Symfony repository](https://github.com/symfony/symfony)

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
@@ -22,7 +23,7 @@ class ClassMapGeneratorTest extends \PHPUnit_Framework_TestCase
public function prepare_workspace()
{
$this->workspace = rtrim(sys_get_temp_dir(), DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR.time().mt_rand(0, 1000);
$this->workspace = sys_get_temp_dir().'/'.microtime(true).'.'.mt_rand();
mkdir($this->workspace, 0777, true);
$this->workspace = realpath($this->workspace);
}
@@ -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 Symfony 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');
@@ -56,10 +58,8 @@ class WinCacheClassLoader
protected $decorated;
/**
* Constructor.
*
* @param string $prefix The WinCache namespace prefix to use.
* @param object $decorated A class loader object that implements the findFile() method.
* @param string $prefix The WinCache namespace prefix to use
* @param object $decorated A class loader object that implements the findFile() method
*
* @throws \RuntimeException
* @throws \InvalidArgumentException
@@ -121,8 +121,10 @@ class WinCacheClassLoader
*/
public function findFile($class)
{
if (false === $file = wincache_ucache_get($this->prefix.$class)) {
wincache_ucache_set($this->prefix.$class, $file = $this->decorated->findFile($class), 0);
$file = wincache_ucache_get($this->prefix.$class, $success);
if (!$success) {
wincache_ucache_set($this->prefix.$class, $file = $this->decorated->findFile($class) ?: null, 0);
}
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
* 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');
@@ -47,19 +49,11 @@ namespace Symfony\Component\ClassLoader;
class XcacheClassLoader
{
private $prefix;
/**
* A class loader object that implements the findFile() method.
*
* @var object
*/
private $decorated;
/**
* Constructor.
*
* @param string $prefix The XCache namespace prefix to use.
* @param object $decorated A class loader object that implements the findFile() method.
* @param string $prefix The XCache namespace prefix to use
* @param object $decorated A class loader object that implements the findFile() method
*
* @throws \RuntimeException
* @throws \InvalidArgumentException
@@ -124,7 +118,7 @@ class XcacheClassLoader
if (xcache_isset($this->prefix.$class)) {
$file = xcache_get($this->prefix.$class);
} else {
$file = $this->decorated->findFile($class);
$file = $this->decorated->findFile($class) ?: null;
xcache_set($this->prefix.$class, $file);
}

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" />