Skip to content

Commit 7b02d69

Browse files
[Config] Fix conditional class existence checks
1 parent 8fbaa79 commit 7b02d69

File tree

3 files changed

+58
-10
lines changed

3 files changed

+58
-10
lines changed

Resource/ClassExistenceResource.php

Lines changed: 41 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,7 @@ class ClassExistenceResource implements SelfCheckingResourceInterface, \Serializ
2828
private $resource;
2929
private $existsStatus;
3030

31-
private static $checkingLevel = 0;
32-
private static $throwingAutoloader;
31+
private static $autoloadLevel = 0;
3332
private static $existsCache = array();
3433

3534
/**
@@ -68,21 +67,17 @@ public function isFresh($timestamp)
6867
if (null !== $exists = &self::$existsCache[$this->resource]) {
6968
$exists = $exists || class_exists($this->resource, false) || interface_exists($this->resource, false) || trait_exists($this->resource, false);
7069
} elseif (self::EXISTS_KO_WITH_THROWING_AUTOLOADER === $this->existsStatus) {
71-
if (null === self::$throwingAutoloader) {
72-
$signalingException = new \ReflectionException();
73-
self::$throwingAutoloader = function () use ($signalingException) { throw $signalingException; };
74-
}
75-
if (!self::$checkingLevel++) {
76-
spl_autoload_register(self::$throwingAutoloader);
70+
if (!self::$autoloadLevel++) {
71+
spl_autoload_register('Symfony\Component\Config\Resource\ClassExistenceResource::throwOnRequiredClass');
7772
}
7873

7974
try {
8075
$exists = class_exists($this->resource) || interface_exists($this->resource, false) || trait_exists($this->resource, false);
8176
} catch (\ReflectionException $e) {
8277
$exists = false;
8378
} finally {
84-
if (!--self::$checkingLevel) {
85-
spl_autoload_unregister(self::$throwingAutoloader);
79+
if (!--self::$autoloadLevel) {
80+
spl_autoload_unregister('Symfony\Component\Config\Resource\ClassExistenceResource::throwOnRequiredClass');
8681
}
8782
}
8883
} else {
@@ -115,4 +110,40 @@ public function unserialize($serialized)
115110
{
116111
list($this->resource, $this->existsStatus) = unserialize($serialized);
117112
}
113+
114+
/**
115+
* @throws \ReflectionException When $class is not found and is required
116+
*/
117+
private static function throwOnRequiredClass($class)
118+
{
119+
$e = new \ReflectionException("Class $class does not exist");
120+
$trace = $e->getTrace();
121+
$autoloadFrame = array(
122+
'function' => 'spl_autoload_call',
123+
'args' => array($class),
124+
);
125+
$i = 1 + array_search($autoloadFrame, $trace, true);
126+
127+
if (isset($trace[$i]['function']) && !isset($trace[$i]['class'])) {
128+
switch ($trace[$i]['function']) {
129+
case 'get_class_methods':
130+
case 'get_class_vars':
131+
case 'get_parent_class':
132+
case 'is_a':
133+
case 'is_subclass_of':
134+
case 'class_exists':
135+
case 'class_implements':
136+
case 'class_parents':
137+
case 'trait_exists':
138+
case 'defined':
139+
case 'interface_exists':
140+
case 'method_exists':
141+
case 'property_exists':
142+
case 'is_callable':
143+
return;
144+
}
145+
}
146+
147+
throw $e;
148+
}
118149
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?php
2+
3+
namespace Symfony\Component\Config\Tests\Fixtures\Resource;
4+
5+
if (!class_exists(MissingClass::class)) {
6+
class ConditionalClass
7+
{
8+
}
9+
}

Tests/Resource/ClassExistenceResourceTest.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
namespace Symfony\Component\Config\Tests\Resource;
1313

1414
use Symfony\Component\Config\Resource\ClassExistenceResource;
15+
use Symfony\Component\Config\Tests\Fixtures\Resource\ConditionalClass;
1516

1617
class ClassExistenceResourceTest extends \PHPUnit_Framework_TestCase
1718
{
@@ -71,4 +72,11 @@ public function testExistsKo()
7172
spl_autoload_unregister($autoloader);
7273
}
7374
}
75+
76+
public function testConditionalClass()
77+
{
78+
$res = new ClassExistenceResource(ConditionalClass::class, ClassExistenceResource::EXISTS_KO_WITH_THROWING_AUTOLOADER);
79+
80+
$this->assertFalse($res->isFresh(0));
81+
}
7482
}

0 commit comments

Comments
 (0)