Compare commits

..

13 Commits
v2.7.8 ... 2.3

Author SHA1 Message Date
Nicolas Grekas
0a01933a8d [ClassLoader] Fix storing not-found classes in APC cache 2016-03-28 10:34:42 +02:00
Nicolas Grekas
d77ac7df59 [Filesystem] Fix transient tests 2016-03-10 15:49:24 +01:00
Javier Eguiluz
355a6b3ee2 Updated all the README files 2016-03-04 08:12:06 +01:00
Fabien Potencier
ac7c135db5 fixed APCu dep version 2016-01-25 15:47:02 +01:00
Geoff
71ff8cc2af [ClassLoader] Use symfony/polyfill-apcu 2016-01-18 12:27:23 -08:00
Fabien Potencier
136d713362 bug #17377 Fix performance (PHP5) and memory (PHP7) issues when using token_get_all (nicolas-grekas, peteward)
This PR was merged into the 2.3 branch.

Discussion
----------

Fix performance (PHP5) and memory (PHP7) issues when using token_get_all

| Q             | A
| ------------- | ---
| Bug fix?      | yes
| New feature?  | no
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | #16868
| License       | MIT
| Doc PR        | -

Although it's not the case anymore on PHP 7, on PHP 5, `is_array` checks are much slower than `isset` checks.

Also from @peteward in #17384:
>  New PHP7 memory manager will not release small buckets to OS automatically in cases exposed by `token_get_all()`. This function call addition specifically for PHP7 will reclaim this memory to keep the footprint down of long processe

> See above ticket and suggested actions by PHP internals team for long-running tasks (https://bugs.php.net/70098) - I think `cache:clear/warmup` on a heavy app justifies this.

> We're running on cloud-based hosting platforms under memory limitations (Platform.sh). When memory is exceeded we're into swap and the cache clearing process goes from seconds to minutes for the initial deployment, which really slows our development workflow and also causes holding page delays.

Commits
-------

e555aad Add gc_mem_caches() call for PHP7 after itoken_get_all() as new memory manager will not release small buckets to OS automatically
d1f72d8 Fix perf and mem issue when using token_get_all
2016-01-15 17:52:13 +01:00
Peter Ward
72df2d4535 Add gc_mem_caches() call for PHP7 after itoken_get_all() as new memory manager will not release small buckets to OS automatically 2016-01-15 10:01:44 +01:00
Nicolas Grekas
a08420fb07 [ClassLoader] Use symfony/polyfill-apcu 2016-01-14 18:42:51 +01:00
Nicolas Grekas
6dc4479622 Fix perf and mem issue when using token_get_all 2016-01-14 14:27:10 +01:00
Diego Saint Esteben
6abee87b00 Update copyright year 2016-01-01 23:53:47 -03:00
Fabien Potencier
f43622ab16 minor #17085 [2.3] Static Code Analysis for Components (kalessil)
This PR was squashed before being merged into the 2.3 branch (closes #17085).

Discussion
----------

[2.3] Static Code Analysis for Components

| Q             | A
| ------------- | ---
| Bug fix?      | no
| New feature?  | no
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | n/a
| License       | MIT
| Doc PR        | n/a

Static Code Analysis with Php Inspections (EA Extended):
    - remaining mkdir race conditions
    - continue miss-usage in switch

Commits
-------

6d303c7 [2.3] Static Code Analysis for Components
2015-12-31 19:24:03 +01:00
Vladimir Reznichenko
7b12dc6915 [2.3] Static Code Analysis for Components 2015-12-31 19:24:01 +01:00
Gregor Harlan
f604d121fa use nowdoc instead of heredoc 2015-12-21 17:05:00 +01:00
43 changed files with 185 additions and 819 deletions

View File

@@ -67,8 +67,8 @@ class ApcClassLoader
*/
public function __construct($prefix, $decorated)
{
if (!extension_loaded('apc')) {
throw new \RuntimeException('Unable to use ApcClassLoader as APC is not enabled.');
if (!function_exists('apcu_fetch')) {
throw new \RuntimeException('Unable to use ApcClassLoader as APC is not installed.');
}
if (!method_exists($decorated, 'findFile')) {
@@ -122,8 +122,10 @@ class ApcClassLoader
*/
public function findFile($class)
{
if (false === $file = apc_fetch($this->prefix.$class)) {
apc_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;

View File

@@ -11,8 +11,6 @@
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.
*
@@ -59,9 +57,6 @@ namespace Symfony\Component\ClassLoader;
*
* @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
{
@@ -76,7 +71,7 @@ class ApcUniversalClassLoader extends UniversalClassLoader
*/
public function __construct($prefix)
{
if (!extension_loaded('apc')) {
if (!function_exists('apcu_fetch')) {
throw new \RuntimeException('Unable to use ApcUniversalClassLoader as APC is not enabled.');
}
@@ -92,8 +87,10 @@ class ApcUniversalClassLoader extends UniversalClassLoader
*/
public function findFile($class)
{
if (false === $file = apc_fetch($this->prefix.$class)) {
apc_store($this->prefix.$class, $file = parent::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
=========
2.4.0
-----
* deprecated the UniversalClassLoader in favor of the ClassLoader class instead
* deprecated the ApcUniversalClassLoader in favor of the ApcClassLoader class instead
* deprecated the DebugUniversalClassLoader in favor of the DebugClassLoader class from the Debug component
* deprecated the DebugClassLoader as it has been moved to the Debug component instead
2.3.0
-----

View File

@@ -53,7 +53,7 @@ class ClassCollectionLoader
$classes = array_diff($classes, $declared);
// the cache is different depending on which classes are already declared
$name = $name.'-'.substr(hash('sha256', implode('|', $classes)), 0, 5);
$name = $name.'-'.substr(md5(implode('|', $classes)), 0, 5);
}
$classes = array_unique($classes);
@@ -116,8 +116,8 @@ class ClassCollectionLoader
}
// cache the core classes
if (!is_dir(dirname($cache))) {
mkdir(dirname($cache), 0777, true);
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);
@@ -149,8 +149,9 @@ class ClassCollectionLoader
$inNamespace = false;
$tokens = token_get_all($source);
for (reset($tokens); false !== $token = current($tokens); next($tokens)) {
if (is_string($token)) {
for ($i = 0; isset($tokens[$i]); ++$i) {
$token = $tokens[$i];
if (!isset($token[1]) || 'b"' === $token) {
$rawChunk .= $token;
} elseif (in_array($token[0], array(T_COMMENT, T_DOC_COMMENT))) {
// strip comments
@@ -162,12 +163,12 @@ class ClassCollectionLoader
$rawChunk .= $token[1];
// namespace name and whitespaces
while (($t = next($tokens)) && is_array($t) && in_array($t[0], array(T_WHITESPACE, T_NS_SEPARATOR, T_STRING))) {
$rawChunk .= $t[1];
while (isset($tokens[++$i][1]) && in_array($tokens[$i][0], array(T_WHITESPACE, T_NS_SEPARATOR, T_STRING))) {
$rawChunk .= $tokens[$i][1];
}
if ('{' === $t) {
if ('{' === $tokens[$i]) {
$inNamespace = false;
prev($tokens);
--$i;
} else {
$rawChunk = rtrim($rawChunk)."\n{";
$inNamespace = true;
@@ -175,8 +176,8 @@ class ClassCollectionLoader
} elseif (T_START_HEREDOC === $token[0]) {
$output .= self::compressCode($rawChunk).$token[1];
do {
$token = next($tokens);
$output .= is_string($token) ? $token : $token[1];
$token = $tokens[++$i];
$output .= isset($token[1]) && 'b"' !== $token ? $token[1] : $token;
} while ($token[0] !== T_END_HEREDOC);
$output .= "\n";
$rawChunk = '';
@@ -192,7 +193,15 @@ class ClassCollectionLoader
$rawChunk .= "}\n";
}
return $output.self::compressCode($rawChunk);
$output .= self::compressCode($rawChunk);
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();
}
return $output;
}
/**

View File

@@ -72,6 +72,11 @@ class ClassMapGenerator
$classes = self::findClasses($path);
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();
}
foreach ($classes as $class) {
$map[$class] = $path;
}
@@ -95,10 +100,10 @@ class ClassMapGenerator
$classes = array();
$namespace = '';
for ($i = 0, $max = count($tokens); $i < $max; ++$i) {
for ($i = 0; isset($tokens[$i]); ++$i) {
$token = $tokens[$i];
if (is_string($token)) {
if (!isset($token[1])) {
continue;
}
@@ -108,9 +113,9 @@ class ClassMapGenerator
case T_NAMESPACE:
$namespace = '';
// If there is a namespace, extract it
while (($t = $tokens[++$i]) && is_array($t)) {
if (in_array($t[0], array(T_STRING, T_NS_SEPARATOR))) {
$namespace .= $t[1];
while (isset($tokens[++$i][1])) {
if (in_array($tokens[$i][0], array(T_STRING, T_NS_SEPARATOR))) {
$namespace .= $tokens[$i][1];
}
}
$namespace .= '\\';
@@ -121,7 +126,7 @@ class ClassMapGenerator
// Skip usage of ::class constant
$isClassConstant = false;
for ($j = $i - 1; $j > 0; --$j) {
if (is_string($tokens[$j])) {
if (!isset($tokens[$j][1])) {
break;
}
@@ -134,14 +139,15 @@ class ClassMapGenerator
}
if ($isClassConstant) {
continue;
break;
}
// Find the classname
while (($t = $tokens[++$i]) && is_array($t)) {
while (isset($tokens[++$i][1])) {
$t = $tokens[$i];
if (T_STRING === $t[0]) {
$class .= $t[1];
} elseif ($class !== '' && T_WHITESPACE == $t[0]) {
} elseif ('' !== $class && T_WHITESPACE === $t[0]) {
break;
}
}

View File

@@ -11,8 +11,6 @@
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.
*
@@ -22,9 +20,6 @@ namespace Symfony\Component\ClassLoader;
*
* @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
{
@@ -40,16 +35,6 @@ class DebugClassLoader
$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.
*/
@@ -89,7 +74,7 @@ class DebugClassLoader
*/
public function findFile($class)
{
return $this->classFinder->findFile($class);
return $this->classFinder->findFile($class) ?: null;
}
/**

View File

@@ -11,15 +11,10 @@
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
{

View File

@@ -1,4 +1,4 @@
Copyright (c) 2004-2015 Fabien Potencier
Copyright (c) 2004-2016 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

@@ -1,94 +0,0 @@
<?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;
/**
* A PSR-4 compatible class loader.
*
* See http://www.php-fig.org/psr/psr-4/
*
* @author Alexander M. Turek <me@derrabus.de>
*/
class Psr4ClassLoader
{
/**
* @var array
*/
private $prefixes = array();
/**
* @param string $prefix
* @param string $baseDir
*/
public function addPrefix($prefix, $baseDir)
{
$prefix = trim($prefix, '\\').'\\';
$baseDir = rtrim($baseDir, DIRECTORY_SEPARATOR).DIRECTORY_SEPARATOR;
$this->prefixes[] = array($prefix, $baseDir);
}
/**
* @param string $class
*
* @return string|null
*/
public function findFile($class)
{
$class = ltrim($class, '\\');
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';
if (file_exists($file)) {
return $file;
}
}
}
}
/**
* @param string $class
*
* @return bool
*/
public function loadClass($class)
{
$file = $this->findFile($class);
if (null !== $file) {
require $file;
return true;
}
return false;
}
/**
* Registers this instance as an autoloader.
*
* @param bool $prepend
*/
public function register($prepend = false)
{
spl_autoload_register(array($this, 'loadClass'), true, $prepend);
}
/**
* Removes this instance from the registered autoloaders.
*/
public function unregister()
{
spl_autoload_unregister(array($this, 'loadClass'));
}
}

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,77 +11,67 @@
namespace Symfony\Component\ClassLoader\Tests;
use Symfony\Component\ClassLoader\ApcClassLoader;
use Symfony\Component\ClassLoader\ClassLoader;
use Symfony\Component\ClassLoader\ApcUniversalClassLoader;
/**
* @requires extension apc
*/
class ApcClassLoaderTest extends \PHPUnit_Framework_TestCase
class ApcUniversalClassLoaderTest extends \PHPUnit_Framework_TestCase
{
protected function setUp()
{
if (!(ini_get('apc.enabled') && ini_get('apc.enable_cli'))) {
$this->markTestSkipped('The apc extension is available, but not enabled.');
if (ini_get('apc.enabled') && ini_get('apc.enable_cli')) {
apcu_clear_cache();
} else {
apc_clear_cache('user');
$this->markTestSkipped('APC is not enabled.');
}
}
protected function tearDown()
{
if (ini_get('apc.enabled') && ini_get('apc.enable_cli')) {
apc_clear_cache('user');
apcu_clear_cache();
}
}
public function testConstructor()
{
$loader = new ClassLoader();
$loader->addPrefix('Apc\Namespaced', __DIR__.DIRECTORY_SEPARATOR.'Fixtures');
$loader = new ApcUniversalClassLoader('test.prefix.');
$loader->registerNamespace('Apc\Namespaced', __DIR__.DIRECTORY_SEPARATOR.'Fixtures');
$loader = new ApcClassLoader('test.prefix.', $loader);
$this->assertEquals($loader->findFile('\Apc\Namespaced\FooBar'), apc_fetch('test.prefix.\Apc\Namespaced\FooBar'), '__construct() takes a prefix as its first argument');
$this->assertEquals($loader->findFile('\Apc\Namespaced\FooBar'), apcu_fetch('test.prefix.\Apc\Namespaced\FooBar'), '__construct() takes a prefix as its first argument');
}
/**
* @dataProvider getLoadClassTests
*/
public function testLoadClass($className, $testClassName, $message)
{
$loader = new ClassLoader();
$loader->addPrefix('Apc\Namespaced', __DIR__.DIRECTORY_SEPARATOR.'Fixtures');
$loader->addPrefix('Apc_Pearlike_', __DIR__.DIRECTORY_SEPARATOR.'Fixtures');
$loader = new ApcClassLoader('test.prefix.', $loader);
$loader->loadClass($testClassName);
$this->assertTrue(class_exists($className), $message);
}
/**
* @dataProvider getLoadClassTests
*/
public function testLoadClass($className, $testClassName, $message)
{
$loader = new ApcUniversalClassLoader('test.prefix.');
$loader->registerNamespace('Apc\Namespaced', __DIR__.DIRECTORY_SEPARATOR.'Fixtures');
$loader->registerPrefix('Apc_Pearlike_', __DIR__.DIRECTORY_SEPARATOR.'Fixtures');
$loader->loadClass($testClassName);
$this->assertTrue(class_exists($className), $message);
}
public function getLoadClassTests()
{
return array(
array('\\Apc\\Namespaced\\Foo', 'Apc\\Namespaced\\Foo', '->loadClass() loads Apc\Namespaced\Foo class'),
array('Apc_Pearlike_Foo', 'Apc_Pearlike_Foo', '->loadClass() loads Apc_Pearlike_Foo class'),
);
);
}
/**
* @dataProvider getLoadClassFromFallbackTests
*/
public function testLoadClassFromFallback($className, $testClassName, $message)
{
$loader = new ClassLoader();
$loader->addPrefix('Apc\Namespaced', __DIR__.DIRECTORY_SEPARATOR.'Fixtures');
$loader->addPrefix('Apc_Pearlike_', __DIR__.DIRECTORY_SEPARATOR.'Fixtures');
$loader->addPrefix('', array(__DIR__.DIRECTORY_SEPARATOR.'Fixtures/Apc/fallback'));
$loader = new ApcClassLoader('test.prefix.fallback', $loader);
$loader->loadClass($testClassName);
$this->assertTrue(class_exists($className), $message);
}
/**
* @dataProvider getLoadClassFromFallbackTests
*/
public function testLoadClassFromFallback($className, $testClassName, $message)
{
$loader = new ApcUniversalClassLoader('test.prefix.fallback');
$loader->registerNamespace('Apc\Namespaced', __DIR__.DIRECTORY_SEPARATOR.'Fixtures');
$loader->registerPrefix('Apc_Pearlike_', __DIR__.DIRECTORY_SEPARATOR.'Fixtures');
$loader->registerNamespaceFallbacks(array(__DIR__.DIRECTORY_SEPARATOR.'Fixtures/Apc/fallback'));
$loader->registerPrefixFallbacks(array(__DIR__.DIRECTORY_SEPARATOR.'Fixtures/Apc/fallback'));
$loader->loadClass($testClassName);
$this->assertTrue(class_exists($className), $message);
}
public function getLoadClassFromFallbackTests()
{
@@ -93,19 +83,18 @@ class ApcClassLoaderTest extends \PHPUnit_Framework_TestCase
);
}
/**
* @dataProvider getLoadClassNamespaceCollisionTests
*/
public function testLoadClassNamespaceCollision($namespaces, $className, $message)
{
$loader = new ClassLoader();
$loader->addPrefixes($namespaces);
/**
* @dataProvider getLoadClassNamespaceCollisionTests
*/
public function testLoadClassNamespaceCollision($namespaces, $className, $message)
{
$loader = new ApcUniversalClassLoader('test.prefix.collision.');
$loader->registerNamespaces($namespaces);
$loader = new ApcClassLoader('test.prefix.collision.', $loader);
$loader->loadClass($className);
$loader->loadClass($className);
$this->assertTrue(class_exists($className), $message);
}
$this->assertTrue(class_exists($className), $message);
}
public function getLoadClassNamespaceCollisionTests()
{
@@ -142,22 +131,20 @@ class ApcClassLoaderTest extends \PHPUnit_Framework_TestCase
'Apc\NamespaceCollision\A\B\Bar',
'->loadClass() loads NamespaceCollision\A\B\Bar from beta.',
),
);
);
}
/**
* @dataProvider getLoadClassPrefixCollisionTests
*/
public function testLoadClassPrefixCollision($prefixes, $className, $message)
{
$loader = new ClassLoader();
$loader->addPrefixes($prefixes);
/**
* @dataProvider getLoadClassPrefixCollisionTests
*/
public function testLoadClassPrefixCollision($prefixes, $className, $message)
{
$loader = new ApcUniversalClassLoader('test.prefix.collision.');
$loader->registerPrefixes($prefixes);
$loader = new ApcClassLoader('test.prefix.collision.', $loader);
$loader->loadClass($className);
$this->assertTrue(class_exists($className), $message);
}
$loader->loadClass($className);
$this->assertTrue(class_exists($className), $message);
}
public function getLoadClassPrefixCollisionTests()
{
@@ -194,6 +181,6 @@ class ApcClassLoaderTest extends \PHPUnit_Framework_TestCase
'ApcPrefixCollision_A_B_Bar',
'->loadClass() loads ApcPrefixCollision_A_B_Bar from beta.',
),
);
);
}
}

View File

@@ -241,26 +241,26 @@ class ClassCollectionLoaderTest extends \PHPUnit_Framework_TestCase
spl_autoload_unregister($r);
$this->assertEquals(<<<EOF
$this->assertEquals(<<<'EOF'
namespace Namespaced
{
class WithComments
{
public static \$loaded = true;
public static $loaded = true;
}
\$string ='string should not be modified {\$string}';
\$heredoc = (<<<HD
$string ='string should not be modified {$string}';
$heredoc = (<<<HD
Heredoc should not be modified {\$string}
Heredoc should not be modified {$string}
HD
);
\$nowdoc =<<<'ND'
$nowdoc =<<<'ND'
Nowdoc should not be modified {\$string}
Nowdoc should not be modified {$string}
ND
@@ -270,7 +270,7 @@ namespace
{
class Pearlike_WithComments
{
public static \$loaded = true;
public static $loaded = true;
}
}
EOF

View File

@@ -72,7 +72,7 @@ class ClassLoaderTest extends \PHPUnit_Framework_TestCase
public function getLoadNonexistentClassTests()
{
return array(
array('\\Pearlike3_Bar', '\\Pearlike3_Bar', '->loadClass() loads non existing Pearlike3_Bar class with a leading slash'),
array('\\Pearlike3_Bar', '\\Pearlike3_Bar', '->loadClass() loads non exising Pearlike3_Bar class with a leading slash'),
);
}

View File

@@ -22,7 +22,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);
}

View File

@@ -0,0 +1,52 @@
<?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 Symfony\Component\ClassLoader\ClassLoader;
use Symfony\Component\ClassLoader\DebugClassLoader;
class DebugClassLoaderTest extends \PHPUnit_Framework_TestCase
{
private $loader;
protected function setUp()
{
$this->loader = new ClassLoader();
spl_autoload_register(array($this->loader, 'loadClass'));
}
protected function tearDown()
{
spl_autoload_unregister(array($this->loader, 'loadClass'));
}
public function testIdempotence()
{
DebugClassLoader::enable();
DebugClassLoader::enable();
$functions = spl_autoload_functions();
foreach ($functions as $function) {
if (is_array($function) && $function[0] instanceof DebugClassLoader) {
$reflClass = new \ReflectionClass($function[0]);
$reflProp = $reflClass->getProperty('classFinder');
$reflProp->setAccessible(true);
$this->assertNotInstanceOf('Symfony\Component\ClassLoader\DebugClassLoader', $reflProp->getValue($function[0]));
return;
}
}
throw new \Exception('DebugClassLoader did not register');
}
}

View File

@@ -1,17 +0,0 @@
<?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

@@ -1,17 +0,0 @@
<?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

@@ -1,17 +0,0 @@
<?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

@@ -1,17 +0,0 @@
<?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

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,17 +0,0 @@
<?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

@@ -1,17 +0,0 @@
<?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

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

View File

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

View File

@@ -1,17 +0,0 @@
<?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

@@ -1,17 +0,0 @@
<?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

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

View File

@@ -1,17 +0,0 @@
<?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

@@ -1,7 +0,0 @@
<?php
namespace Acme\DemoLib;
class Class_With_Underscores
{
}

View File

@@ -1,7 +0,0 @@
<?php
namespace Acme\DemoLib;
class Foo
{
}

View File

@@ -1,7 +0,0 @@
<?php
namespace Acme\DemoLib\Lets\Go\Deeper;
class Class_With_Underscores
{
}

View File

@@ -1,7 +0,0 @@
<?php
namespace Acme\DemoLib\Lets\Go\Deeper;
class Foo
{
}

View File

@@ -1,190 +0,0 @@
<?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 Symfony\Component\ClassLoader\ApcUniversalClassLoader;
/**
* @group legacy
* @requires extension apc
*/
class LegacyApcUniversalClassLoaderTest extends \PHPUnit_Framework_TestCase
{
protected function setUp()
{
if (ini_get('apc.enabled') && ini_get('apc.enable_cli')) {
apc_clear_cache('user');
} else {
$this->markTestSkipped('APC is not enabled.');
}
}
protected function tearDown()
{
if (ini_get('apc.enabled') && ini_get('apc.enable_cli')) {
apc_clear_cache('user');
}
}
public function testConstructor()
{
$loader = new ApcUniversalClassLoader('test.prefix.');
$loader->registerNamespace('LegacyApc\Namespaced', __DIR__.DIRECTORY_SEPARATOR.'Fixtures');
$this->assertEquals($loader->findFile('\LegacyApc\Namespaced\FooBar'), apc_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

@@ -1,71 +0,0 @@
<?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 Symfony\Component\ClassLoader\Psr4ClassLoader;
class Psr4ClassLoaderTest extends \PHPUnit_Framework_TestCase
{
/**
* @param string $className
* @dataProvider getLoadClassTests
*/
public function testLoadClass($className)
{
$loader = new Psr4ClassLoader();
$loader->addPrefix(
'Acme\\DemoLib',
__DIR__.DIRECTORY_SEPARATOR.'Fixtures'.DIRECTORY_SEPARATOR.'psr-4'
);
$loader->loadClass($className);
$this->assertTrue(class_exists($className), sprintf('loadClass() should load %s', $className));
}
/**
* @return array
*/
public function getLoadClassTests()
{
return array(
array('Acme\\DemoLib\\Foo'),
array('Acme\\DemoLib\\Class_With_Underscores'),
array('Acme\\DemoLib\\Lets\\Go\\Deeper\\Foo'),
array('Acme\\DemoLib\\Lets\\Go\\Deeper\\Class_With_Underscores'),
);
}
/**
* @param string $className
* @dataProvider getLoadNonexistentClassTests
*/
public function testLoadNonexistentClass($className)
{
$loader = new Psr4ClassLoader();
$loader->addPrefix(
'Acme\\DemoLib',
__DIR__.DIRECTORY_SEPARATOR.'Fixtures'.DIRECTORY_SEPARATOR.'psr-4'
);
$loader->loadClass($className);
$this->assertFalse(class_exists($className), sprintf('loadClass() should not load %s', $className));
}
/**
* @return array
*/
public function getLoadNonexistentClassTests()
{
return array(
array('Acme\\DemoLib\\I_Do_Not_Exist'),
array('UnknownVendor\\SomeLib\\I_Do_Not_Exist'),
);
}
}

View File

@@ -13,10 +13,7 @@ namespace Symfony\Component\ClassLoader\Tests;
use Symfony\Component\ClassLoader\UniversalClassLoader;
/**
* @group legacy
*/
class LegacyUniversalClassLoaderTest extends \PHPUnit_Framework_TestCase
class UniversalClassLoaderTest extends \PHPUnit_Framework_TestCase
{
/**
* @dataProvider getLoadClassTests

View File

@@ -11,8 +11,6 @@
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.
*
@@ -57,9 +55,6 @@ namespace Symfony\Component\ClassLoader;
* 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
{

View File

@@ -123,8 +123,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

@@ -126,7 +126,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,20 +17,22 @@
],
"minimum-stability": "dev",
"require": {
"php": ">=5.3.9"
"php": ">=5.3.3",
"symfony/polyfill-apcu": "~1.1"
},
"require-dev": {
"symfony/finder": "~2.0,>=2.0.5"
},
"autoload": {
"psr-4": { "Symfony\\Component\\ClassLoader\\": "" },
"psr-0": { "Symfony\\Component\\ClassLoader\\": "" },
"exclude-from-classmap": [
"/Tests/"
]
},
"target-dir": "Symfony/Component/ClassLoader",
"extra": {
"branch-alias": {
"dev-master": "2.7-dev"
"dev-master": "2.3-dev"
}
}
}