Merge branch '3.4'

* 3.4:
  [Config] Always protect ClassExistenceResource against bad parents
This commit is contained in:
Nicolas Grekas 2017-06-02 20:47:32 +02:00
commit 9a8f779a5d
4 changed files with 27 additions and 35 deletions

View File

@ -21,25 +21,21 @@ namespace Symfony\Component\Config\Resource;
*/
class ClassExistenceResource implements SelfCheckingResourceInterface, \Serializable
{
const EXISTS_OK = 1;
const EXISTS_KO = 0;
const EXISTS_KO_WITH_THROWING_AUTOLOADER = -1;
private $resource;
private $existsStatus;
private $exists;
private static $autoloadLevel = 0;
private static $existsCache = array();
/**
* @param string $resource The fully-qualified class name
* @param int|null $existsStatus One of the self::EXISTS_* const if the existency check has already been done
* @param string $resource The fully-qualified class name
* @param bool|null $exists Boolean when the existency check has already been done
*/
public function __construct($resource, $existsStatus = null)
public function __construct($resource, $exists = null)
{
$this->resource = $resource;
if (null !== $existsStatus) {
$this->existsStatus = (int) $existsStatus;
if (null !== $exists) {
$this->exists = (bool) $exists;
}
}
@ -64,11 +60,13 @@ class ClassExistenceResource implements SelfCheckingResourceInterface, \Serializ
*/
public function isFresh($timestamp)
{
$loaded = class_exists($this->resource, false) || interface_exists($this->resource, false) || trait_exists($this->resource, false);
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) {
$exists = $exists || $loaded;
} elseif (!$exists = $loaded) {
if (!self::$autoloadLevel++) {
spl_autoload_register('Symfony\Component\Config\Resource\ClassExistenceResource::throwOnRequiredClass');
spl_autoload_register(__CLASS__.'::throwOnRequiredClass');
}
try {
@ -77,18 +75,16 @@ class ClassExistenceResource implements SelfCheckingResourceInterface, \Serializ
$exists = false;
} finally {
if (!--self::$autoloadLevel) {
spl_autoload_unregister('Symfony\Component\Config\Resource\ClassExistenceResource::throwOnRequiredClass');
spl_autoload_unregister(__CLASS__.'::throwOnRequiredClass');
}
}
} else {
$exists = class_exists($this->resource) || interface_exists($this->resource, false) || trait_exists($this->resource, false);
}
if (null === $this->existsStatus) {
$this->existsStatus = $exists ? self::EXISTS_OK : self::EXISTS_KO;
if (null === $this->exists) {
$this->exists = $exists;
}
return self::EXISTS_OK === $this->existsStatus xor !$exists;
return $this->exists xor !$exists;
}
/**
@ -96,11 +92,11 @@ class ClassExistenceResource implements SelfCheckingResourceInterface, \Serializ
*/
public function serialize()
{
if (null === $this->existsStatus) {
if (null === $this->exists) {
$this->isFresh(0);
}
return serialize(array($this->resource, $this->existsStatus));
return serialize(array($this->resource, $this->exists));
}
/**
@ -108,7 +104,7 @@ class ClassExistenceResource implements SelfCheckingResourceInterface, \Serializ
*/
public function unserialize($serialized)
{
list($this->resource, $this->existsStatus) = unserialize($serialized);
list($this->resource, $this->exists) = unserialize($serialized);
}
/**

View File

@ -66,7 +66,7 @@ EOF
$loadedClass = 123;
$res = new ClassExistenceResource('MissingFooClass', ClassExistenceResource::EXISTS_KO);
$res = new ClassExistenceResource('MissingFooClass', false);
$this->assertSame(123, $loadedClass);
} finally {
@ -76,7 +76,7 @@ EOF
public function testConditionalClass()
{
$res = new ClassExistenceResource(ConditionalClass::class, ClassExistenceResource::EXISTS_KO_WITH_THROWING_AUTOLOADER);
$res = new ClassExistenceResource(ConditionalClass::class, false);
$this->assertFalse($res->isFresh(0));
}

View File

@ -376,7 +376,7 @@ class AutowirePass extends AbstractRecursivePass
return;
}
if ($definition->isDeprecated() || !$reflectionClass = $this->container->getReflectionClass($definition->getClass(), true)) {
if ($definition->isDeprecated() || !$reflectionClass = $this->container->getReflectionClass($definition->getClass())) {
return;
}
@ -428,7 +428,7 @@ class AutowirePass extends AbstractRecursivePass
*/
private function createAutowiredDefinition($type)
{
if (!($typeHint = $this->container->getReflectionClass($type, true)) || !$typeHint->isInstantiable()) {
if (!($typeHint = $this->container->getReflectionClass($type)) || !$typeHint->isInstantiable()) {
return;
}
@ -462,7 +462,7 @@ class AutowirePass extends AbstractRecursivePass
private function createTypeNotFoundMessage(TypedReference $reference, $label)
{
if (!$r = $this->container->getReflectionClass($type = $reference->getType(), true)) {
if (!$r = $this->container->getReflectionClass($type = $reference->getType())) {
$message = sprintf('has type "%s" but this class does not exist.', $type);
} else {
$message = $this->container->has($type) ? 'this service is abstract' : 'no such service exists';

View File

@ -336,13 +336,12 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
* Retrieves the requested reflection class and registers it for resource tracking.
*
* @param string $class
* @param bool $koWithThrowingAutoloader Whether autoload should be protected against bad parents or not
*
* @return \ReflectionClass|null
*
* @final
*/
public function getReflectionClass($class, $koWithThrowingAutoloader = false)
public function getReflectionClass($class)
{
if (!$class = $this->getParameterBag()->resolveValue($class)) {
return;
@ -352,12 +351,9 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
try {
if (isset($this->classReflectors[$class])) {
$classReflector = $this->classReflectors[$class];
} elseif ($koWithThrowingAutoloader) {
$resource = new ClassExistenceResource($class, ClassExistenceResource::EXISTS_KO_WITH_THROWING_AUTOLOADER);
$classReflector = $resource->isFresh(0) ? false : new \ReflectionClass($class);
} else {
$classReflector = new \ReflectionClass($class);
$resource = new ClassExistenceResource($class, false);
$classReflector = $resource->isFresh(0) ? false : new \ReflectionClass($class);
}
} catch (\ReflectionException $e) {
$classReflector = false;
@ -365,7 +361,7 @@ class ContainerBuilder extends Container implements TaggedContainerInterface
if ($this->trackResources) {
if (!$classReflector) {
$this->addResource($resource ?: new ClassExistenceResource($class, ClassExistenceResource::EXISTS_KO));
$this->addResource($resource ?: new ClassExistenceResource($class, false));
} elseif (!$classReflector->isInternal()) {
$path = $classReflector->getFileName();