bug #10861 [Debug] enhance perf of DebugClassLoader (nicolas-grekas)
This PR was merged into the 2.3-dev branch.
Discussion
----------
[Debug] enhance perf of DebugClassLoader
| Q | A
| ------------- | ---
| Bug fix? | yes
| New feature? | no
| BC breaks? | no
| Deprecations? | no
| Tests pass? | yes
| Fixed tickets | #10860
| License | MIT
| Doc PR | none
- restricts the check for case mismatch to Windows and Darwin,
- on Darwin, use glob() trick to bypass more extensive checks
Commits
-------
485e047
[Debug] enhance perf of DebugClassLoader
This commit is contained in:
commit
ff9f06b978
@ -29,6 +29,7 @@ class DebugClassLoader
|
||||
private $classLoader;
|
||||
private $isFinder;
|
||||
private $wasFinder;
|
||||
private static $caseCheck;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
@ -49,6 +50,10 @@ class DebugClassLoader
|
||||
$this->classLoader = $classLoader;
|
||||
$this->isFinder = is_array($classLoader) && method_exists($classLoader[0], 'findFile');
|
||||
}
|
||||
|
||||
if (!isset(self::$caseCheck)) {
|
||||
self::$caseCheck = false !== stripos(PHP_OS, 'win') ? (false !== stripos(PHP_OS, 'darwin') ? 2 : 1) : 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -162,9 +167,13 @@ class DebugClassLoader
|
||||
|
||||
$exists = class_exists($class, false) || interface_exists($class, false) || (function_exists('trait_exists') && trait_exists($class, false));
|
||||
|
||||
if ('\\' === $class[0]) {
|
||||
$class = substr($class, 1);
|
||||
}
|
||||
|
||||
if ($exists) {
|
||||
$name = new \ReflectionClass($class);
|
||||
$name = $name->getName();
|
||||
$refl = new \ReflectionClass($class);
|
||||
$name = $refl->getName();
|
||||
|
||||
if ($name !== $class) {
|
||||
throw new \RuntimeException(sprintf('Case mismatch between loaded and declared class names: %s vs %s', $class, $name));
|
||||
@ -172,30 +181,35 @@ class DebugClassLoader
|
||||
}
|
||||
|
||||
if ($file) {
|
||||
if ('\\' == $class[0]) {
|
||||
$class = substr($class, 1);
|
||||
if (!$exists) {
|
||||
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));
|
||||
}
|
||||
|
||||
if (preg_match('#([/\\\\][a-zA-Z_\x7F-\xFF][a-zA-Z0-9_\x7F-\xFF]*)+\.(php|hh)$#', $file, $tail)) {
|
||||
if (self::$caseCheck && preg_match('#([/\\\\][a-zA-Z_\x7F-\xFF][a-zA-Z0-9_\x7F-\xFF]*)+\.(php|hh)$#D', $file, $tail)) {
|
||||
$tail = $tail[0];
|
||||
$real = realpath($file);
|
||||
$real = $refl->getFilename();
|
||||
|
||||
if (false !== stripos(PHP_OS, 'darwin')) {
|
||||
// realpath() on MacOSX doesn't normalize the case of characters,
|
||||
// let's do it ourselves. This is tricky.
|
||||
if (2 === self::$caseCheck) {
|
||||
// realpath() on MacOSX doesn't normalize the case of characters
|
||||
$cwd = getcwd();
|
||||
$basename = strrpos($real, '/');
|
||||
chdir(substr($real, 0, $basename));
|
||||
$basename = substr($real, $basename + 1);
|
||||
$real = getcwd().'/';
|
||||
$h = opendir('.');
|
||||
while (false !== $f = readdir($h)) {
|
||||
if (0 === strcasecmp($f, $basename)) {
|
||||
$real .= $f;
|
||||
break;
|
||||
// glob() patterns are case-sensitive even if the underlying fs is not
|
||||
if (!in_array($basename, glob($basename.'*', GLOB_NOSORT), true)) {
|
||||
$real = getcwd().'/';
|
||||
$h = opendir('.');
|
||||
while (false !== $f = readdir($h)) {
|
||||
if (0 === strcasecmp($f, $basename)) {
|
||||
$real .= $f;
|
||||
break;
|
||||
}
|
||||
}
|
||||
closedir($h);
|
||||
}
|
||||
closedir($h);
|
||||
chdir($cwd);
|
||||
}
|
||||
|
||||
@ -206,14 +220,6 @@ class DebugClassLoader
|
||||
}
|
||||
}
|
||||
|
||||
if (!$exists) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user