Skip to content

Commit c20d7e2

Browse files
[Config] never try loading failed classes twice with ClassExistenceResource
1 parent 7a13ea3 commit c20d7e2

File tree

3 files changed

+55
-8
lines changed

3 files changed

+55
-8
lines changed

src/Symfony/Component/Config/Resource/ClassExistenceResource.php

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ public function __construct($resource, $exists = null)
3636
{
3737
$this->resource = $resource;
3838
if (null !== $exists) {
39-
$this->exists = (bool) $exists;
39+
$this->exists = [(bool) $exists, null];
4040
}
4141
}
4242

@@ -65,26 +65,33 @@ public function isFresh($timestamp)
6565
{
6666
$loaded = class_exists($this->resource, false) || interface_exists($this->resource, false) || trait_exists($this->resource, false);
6767

68-
if (null !== $exists = &self::$existsCache[(int) (0 >= $timestamp)][$this->resource]) {
69-
$exists = $exists || $loaded;
70-
} elseif (!$exists = $loaded) {
68+
if (null !== $exists = &self::$existsCache[$this->resource]) {
69+
if ($loaded) {
70+
$exists = [true, null];
71+
} elseif (0 >= $timestamp && !$exists[0] && null !== $exists[1]) {
72+
throw new \ReflectionException($exists[1]);
73+
}
74+
} elseif ([false, null] === $exists = [$loaded, null]) {
7175
if (!self::$autoloadLevel++) {
7276
spl_autoload_register(__CLASS__.'::throwOnRequiredClass');
7377
}
7478
$autoloadedClass = self::$autoloadedClass;
7579
self::$autoloadedClass = ltrim($this->resource, '\\');
7680

7781
try {
78-
$exists = class_exists($this->resource) || interface_exists($this->resource, false) || trait_exists($this->resource, false);
82+
$exists[0] = class_exists($this->resource) || interface_exists($this->resource, false) || trait_exists($this->resource, false);
7983
} catch (\Exception $e) {
84+
$exists[1] = $e->getMessage();
85+
8086
try {
8187
self::throwOnRequiredClass($this->resource, $e);
8288
} catch (\ReflectionException $e) {
8389
if (0 >= $timestamp) {
84-
unset(self::$existsCache[1][$this->resource]);
8590
throw $e;
8691
}
8792
}
93+
} catch (\Throwable $e) {
94+
$exists[1] = $e->getMessage();
8895
} finally {
8996
self::$autoloadedClass = $autoloadedClass;
9097
if (!--self::$autoloadLevel) {
@@ -97,7 +104,7 @@ public function isFresh($timestamp)
97104
$this->exists = $exists;
98105
}
99106

100-
return $this->exists xor !$exists;
107+
return $this->exists[0] xor !$exists[0];
101108
}
102109

103110
/**
@@ -118,6 +125,10 @@ public function serialize()
118125
public function unserialize($serialized)
119126
{
120127
list($this->resource, $this->exists) = unserialize($serialized);
128+
129+
if (\is_bool($this->exists)) {
130+
$this->exists = [$this->exists, null];
131+
}
121132
}
122133

123134
/**
@@ -155,7 +166,17 @@ public static function throwOnRequiredClass($class, \Exception $previous = null)
155166
throw $previous;
156167
}
157168

158-
$e = new \ReflectionException(sprintf('Class "%s" not found while loading "%s".', $class, self::$autoloadedClass), 0, $previous);
169+
$message = sprintf('Class "%s" not found.', $class);
170+
171+
if (self::$autoloadedClass !== $class) {
172+
$message = substr_replace($message, sprintf(' while loading "%s"', self::$autoloadedClass), -1, 0);
173+
}
174+
175+
if (null !== $previous) {
176+
$message = $previous->getMessage();
177+
}
178+
179+
$e = new \ReflectionException($message, 0, $previous);
159180

160181
if (null !== $previous) {
161182
throw $e;
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<?php
2+
3+
namespace Symfony\Component\Config\Tests\Fixtures;
4+
5+
class FileNameMismatchOnPurpose
6+
{
7+
}

src/Symfony/Component/Config/Tests/Resource/ClassExistenceResourceTest.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
use PHPUnit\Framework\TestCase;
1515
use Symfony\Component\Config\Resource\ClassExistenceResource;
16+
use Symfony\Component\Config\Tests\Fixtures\BadFileName;
1617
use Symfony\Component\Config\Tests\Fixtures\BadParent;
1718
use Symfony\Component\Config\Tests\Fixtures\Resource\ConditionalClass;
1819

@@ -90,6 +91,24 @@ public function testBadParentWithNoTimestamp()
9091
$res->isFresh(0);
9192
}
9293

94+
public function testBadFileName()
95+
{
96+
$this->expectException('ReflectionException');
97+
$this->expectExceptionMessage('The autoloader expected class "Symfony\Component\Config\Tests\Fixtures\BadFileName" to be defined in file');
98+
99+
$res = new ClassExistenceResource(BadFileName::class, false);
100+
$res->isFresh(0);
101+
}
102+
103+
public function testBadFileNameBis()
104+
{
105+
$this->expectException('ReflectionException');
106+
$this->expectExceptionMessage('The autoloader expected class "Symfony\Component\Config\Tests\Fixtures\BadFileName" to be defined in file');
107+
108+
$res = new ClassExistenceResource(BadFileName::class, false);
109+
$res->isFresh(0);
110+
}
111+
93112
public function testConditionalClass()
94113
{
95114
$res = new ClassExistenceResource(ConditionalClass::class, false);

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy