bug #10776 [Debug] fix #10771 DebugClassLoader can't load PSR4 libs (nicolas-grekas)

This PR was merged into the 2.5-dev branch.

Discussion
----------

[Debug] fix #10771 DebugClassLoader can't load PSR4 libs

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

Commits
-------

e3566c2 [Debug] fix #10771 DebugClassLoader can't load PSR4 libs
This commit is contained in:
Fabien Potencier 2014-04-25 09:03:21 +02:00
commit 4c2405f300
2 changed files with 37 additions and 28 deletions

View File

@ -176,32 +176,37 @@ class DebugClassLoader
$class = substr($class, 1);
}
$i = 0;
$tail = DIRECTORY_SEPARATOR . str_replace('\\', DIRECTORY_SEPARATOR, $class).'.php';
$len = strlen($tail);
if (preg_match('#([/\\\\][a-zA-Z_\x7F-\xFF][a-zA-Z0-9_\x7F-\xFF]*)+\.(php|hh)$#', $file, $tail)) {
$tail = $tail[0];
$real = realpath($file);
do {
$tail = substr($tail, $i);
$len -= $i;
if (0 === substr_compare($file, $tail, -$len, $len, true)) {
if (0 !== substr_compare($file, $tail, -$len, $len, false)) {
if (method_exists($this->classLoader[0], 'getClassMap')) {
$map = $this->classLoader[0]->getClassMap();
} else {
$map = array();
}
if (! isset($map[$class])) {
throw new \RuntimeException(sprintf('Case mismatch between class and source file names: %s vs %s', $class, $file));
if (false !== stripos(PHP_OS, 'darwin')) {
// realpath() on MacOSX doesn't normalize the case of characters,
// let's do it ourselves. This is tricky.
$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;
}
}
break;
closedir($h);
chdir($cwd);
}
} while (false !== $i = strpos($tail, DIRECTORY_SEPARATOR, 1));
if (! $exists) {
if ( 0 === substr_compare($real, $tail, -strlen($tail), strlen($tail), true)
&& 0 !== substr_compare($real, $tail, -strlen($tail), strlen($tail), false)
) {
throw new \RuntimeException(sprintf('Case mismatch between class and source file names: %s vs %s', $class, $real));
}
}
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));
}

View File

@ -27,7 +27,7 @@ class DebugClassLoaderTest extends \PHPUnit_Framework_TestCase
{
$this->errorReporting = error_reporting(E_ALL | E_STRICT);
$this->loader = new ClassLoader();
spl_autoload_register(array($this->loader, 'loadClass'));
spl_autoload_register(array($this->loader, 'loadClass'), true, true);
DebugClassLoader::enable();
}
@ -68,7 +68,7 @@ class DebugClassLoaderTest extends \PHPUnit_Framework_TestCase
// See below: this will fail with parse error
// but this should not be @-silenced.
@ class_exists(__NAMESPACE__.'\TestingUnsilencing', true);
@class_exists(__NAMESPACE__.'\TestingUnsilencing', true);
ini_set('log_errors', $bak[0]);
ini_set('display_errors', $bak[1]);
@ -138,6 +138,10 @@ class DebugClassLoaderTest extends \PHPUnit_Framework_TestCase
*/
public function testFileCaseMismatch()
{
if (!file_exists(__DIR__.'/Fixtures/CaseMismatch.php')) {
$this->markTestSkipped('Can only be run on case insensitive filesystems');
}
class_exists(__NAMESPACE__.'\Fixtures\CaseMismatch', true);
}
@ -168,7 +172,7 @@ class ClassLoader
public function getClassMap()
{
return array(__NAMESPACE__.'\Fixtures\NotPSR0bis' => __DIR__ . '/Fixtures/notPsr0Bis.php');
return array(__NAMESPACE__.'\Fixtures\NotPSR0bis' => __DIR__.'/Fixtures/notPsr0Bis.php');
}
public function findFile($class)
@ -180,13 +184,13 @@ class ClassLoader
} elseif (__NAMESPACE__.'\TestingCaseMismatch' === $class) {
eval('namespace '.__NAMESPACE__.'; class TestingCaseMisMatch {}');
} elseif (__NAMESPACE__.'\Fixtures\CaseMismatch' === $class) {
return __DIR__ . '/Fixtures/casemismatch.php';
return __DIR__.'/Fixtures/CaseMismatch.php';
} elseif (__NAMESPACE__.'\Fixtures\Psr4CaseMismatch' === $class) {
return __DIR__ . '/Fixtures/psr4/Psr4CaseMismatch.php';
return __DIR__.'/Fixtures/psr4/Psr4CaseMismatch.php';
} elseif (__NAMESPACE__.'\Fixtures\NotPSR0' === $class) {
return __DIR__ . '/Fixtures/reallyNotPsr0.php';
return __DIR__.'/Fixtures/reallyNotPsr0.php';
} elseif (__NAMESPACE__.'\Fixtures\NotPSR0bis' === $class) {
return __DIR__ . '/Fixtures/notPsr0Bis.php';
return __DIR__.'/Fixtures/notPsr0Bis.php';
}
}
}