bug #21527 [Config] Fix conditional class existence checks (nicolas-grekas)
This PR was merged into the 3.3-dev branch.
Discussion
----------
[Config] Fix conditional class existence checks
| Q | A
| ------------- | ---
| Branch? | master
| Bug fix? | yes
| New feature? | no
| BC breaks? | no
| Deprecations? | no
| Tests pass? | yes
| Fixed tickets | -
| License | MIT
| Doc PR | -
Commits
-------
686af61
[Config] Fix conditional class existence checks
This commit is contained in:
commit
a736458fb5
@ -28,8 +28,7 @@ class ClassExistenceResource implements SelfCheckingResourceInterface, \Serializ
|
||||
private $resource;
|
||||
private $existsStatus;
|
||||
|
||||
private static $checkingLevel = 0;
|
||||
private static $throwingAutoloader;
|
||||
private static $autoloadLevel = 0;
|
||||
private static $existsCache = array();
|
||||
|
||||
/**
|
||||
@ -68,12 +67,8 @@ class ClassExistenceResource implements SelfCheckingResourceInterface, \Serializ
|
||||
if (null !== $exists = &self::$existsCache[$this->resource]) {
|
||||
$exists = $exists || class_exists($this->resource, false) || interface_exists($this->resource, false) || trait_exists($this->resource, false);
|
||||
} elseif (self::EXISTS_KO_WITH_THROWING_AUTOLOADER === $this->existsStatus) {
|
||||
if (null === self::$throwingAutoloader) {
|
||||
$signalingException = new \ReflectionException();
|
||||
self::$throwingAutoloader = function () use ($signalingException) { throw $signalingException; };
|
||||
}
|
||||
if (!self::$checkingLevel++) {
|
||||
spl_autoload_register(self::$throwingAutoloader);
|
||||
if (!self::$autoloadLevel++) {
|
||||
spl_autoload_register('Symfony\Component\Config\Resource\ClassExistenceResource::throwOnRequiredClass');
|
||||
}
|
||||
|
||||
try {
|
||||
@ -81,8 +76,8 @@ class ClassExistenceResource implements SelfCheckingResourceInterface, \Serializ
|
||||
} catch (\ReflectionException $e) {
|
||||
$exists = false;
|
||||
} finally {
|
||||
if (!--self::$checkingLevel) {
|
||||
spl_autoload_unregister(self::$throwingAutoloader);
|
||||
if (!--self::$autoloadLevel) {
|
||||
spl_autoload_unregister('Symfony\Component\Config\Resource\ClassExistenceResource::throwOnRequiredClass');
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -115,4 +110,40 @@ class ClassExistenceResource implements SelfCheckingResourceInterface, \Serializ
|
||||
{
|
||||
list($this->resource, $this->existsStatus) = unserialize($serialized);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \ReflectionException When $class is not found and is required
|
||||
*/
|
||||
private static function throwOnRequiredClass($class)
|
||||
{
|
||||
$e = new \ReflectionException("Class $class does not exist");
|
||||
$trace = $e->getTrace();
|
||||
$autoloadFrame = array(
|
||||
'function' => 'spl_autoload_call',
|
||||
'args' => array($class),
|
||||
);
|
||||
$i = 1 + array_search($autoloadFrame, $trace, true);
|
||||
|
||||
if (isset($trace[$i]['function']) && !isset($trace[$i]['class'])) {
|
||||
switch ($trace[$i]['function']) {
|
||||
case 'get_class_methods':
|
||||
case 'get_class_vars':
|
||||
case 'get_parent_class':
|
||||
case 'is_a':
|
||||
case 'is_subclass_of':
|
||||
case 'class_exists':
|
||||
case 'class_implements':
|
||||
case 'class_parents':
|
||||
case 'trait_exists':
|
||||
case 'defined':
|
||||
case 'interface_exists':
|
||||
case 'method_exists':
|
||||
case 'property_exists':
|
||||
case 'is_callable':
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace Symfony\Component\Config\Tests\Fixtures\Resource;
|
||||
|
||||
if (!class_exists(MissingClass::class)) {
|
||||
class ConditionalClass
|
||||
{
|
||||
}
|
||||
}
|
@ -12,6 +12,7 @@
|
||||
namespace Symfony\Component\Config\Tests\Resource;
|
||||
|
||||
use Symfony\Component\Config\Resource\ClassExistenceResource;
|
||||
use Symfony\Component\Config\Tests\Fixtures\Resource\ConditionalClass;
|
||||
|
||||
class ClassExistenceResourceTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
@ -71,4 +72,11 @@ EOF
|
||||
spl_autoload_unregister($autoloader);
|
||||
}
|
||||
}
|
||||
|
||||
public function testConditionalClass()
|
||||
{
|
||||
$res = new ClassExistenceResource(ConditionalClass::class, ClassExistenceResource::EXISTS_KO_WITH_THROWING_AUTOLOADER);
|
||||
|
||||
$this->assertFalse($res->isFresh(0));
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user