mirror of
https://github.com/symfony/class-loader.git
synced 2026-03-24 17:22:11 +01:00
Compare commits
22 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7d362c2271 | ||
|
|
f5df9e4df1 | ||
|
|
d77ac7df59 | ||
|
|
f3037a1d54 | ||
|
|
eb9cd31d2f | ||
|
|
355a6b3ee2 | ||
|
|
517ab0554b | ||
|
|
283e453827 | ||
|
|
5fe4b278a6 | ||
|
|
60726000db | ||
|
|
ac7c135db5 | ||
|
|
2e5d508d14 | ||
|
|
240e348e95 | ||
|
|
0f257ff274 | ||
|
|
71ff8cc2af | ||
|
|
d700058274 | ||
|
|
136d713362 | ||
|
|
f1c1790c27 | ||
|
|
252b21d760 | ||
|
|
72df2d4535 | ||
|
|
a08420fb07 | ||
|
|
6dc4479622 |
@@ -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,8 @@ class ApcClassLoader
|
||||
*/
|
||||
public function findFile($class)
|
||||
{
|
||||
if (false === $file = apc_fetch($this->prefix.$class)) {
|
||||
apc_store($this->prefix.$class, $file = $this->decorated->findFile($class));
|
||||
if (false === $file = apcu_fetch($this->prefix.$class)) {
|
||||
apcu_store($this->prefix.$class, $file = $this->decorated->findFile($class));
|
||||
}
|
||||
|
||||
return $file;
|
||||
|
||||
@@ -76,7 +76,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 +92,8 @@ 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));
|
||||
if (false === $file = apcu_fetch($this->prefix.$class)) {
|
||||
apcu_store($this->prefix.$class, $file = parent::findFile($class));
|
||||
}
|
||||
|
||||
return $file;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -138,10 +143,11 @@ class ClassMapGenerator
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
85
README.md
85
README.md
@@ -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)
|
||||
|
||||
@@ -14,24 +14,21 @@ namespace Symfony\Component\ClassLoader\Tests;
|
||||
use Symfony\Component\ClassLoader\ApcClassLoader;
|
||||
use Symfony\Component\ClassLoader\ClassLoader;
|
||||
|
||||
/**
|
||||
* @requires extension apc
|
||||
*/
|
||||
class ApcClassLoaderTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
protected function setUp()
|
||||
{
|
||||
if (ini_get('apc.enabled') && ini_get('apc.enable_cli')) {
|
||||
apc_clear_cache('user');
|
||||
if (!(ini_get('apc.enabled') && ini_get('apc.enable_cli'))) {
|
||||
$this->markTestSkipped('The apc extension is not enabled.');
|
||||
} else {
|
||||
$this->markTestSkipped('APC is not enabled.');
|
||||
apcu_clear_cache();
|
||||
}
|
||||
}
|
||||
|
||||
protected function tearDown()
|
||||
{
|
||||
if (ini_get('apc.enabled') && ini_get('apc.enable_cli')) {
|
||||
apc_clear_cache('user');
|
||||
apcu_clear_cache();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,7 +39,7 @@ class ApcClassLoaderTest extends \PHPUnit_Framework_TestCase
|
||||
|
||||
$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');
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -15,14 +15,13 @@ 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');
|
||||
apcu_clear_cache();
|
||||
} else {
|
||||
$this->markTestSkipped('APC is not enabled.');
|
||||
}
|
||||
@@ -31,7 +30,7 @@ class LegacyApcUniversalClassLoaderTest extends \PHPUnit_Framework_TestCase
|
||||
protected function tearDown()
|
||||
{
|
||||
if (ini_get('apc.enabled') && ini_get('apc.enable_cli')) {
|
||||
apc_clear_cache('user');
|
||||
apcu_clear_cache();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,7 +39,7 @@ class LegacyApcUniversalClassLoaderTest extends \PHPUnit_Framework_TestCase
|
||||
$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');
|
||||
$this->assertEquals($loader->findFile('\LegacyApc\Namespaced\FooBar'), apcu_fetch('test.prefix.\LegacyApc\Namespaced\FooBar'), '__construct() takes a prefix as its first argument');
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -17,7 +17,8 @@
|
||||
],
|
||||
"minimum-stability": "dev",
|
||||
"require": {
|
||||
"php": ">=5.3.9"
|
||||
"php": ">=5.3.9",
|
||||
"symfony/polyfill-apcu": "~1.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/finder": "~2.0,>=2.0.5|~3.0.0"
|
||||
|
||||
Reference in New Issue
Block a user