diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Compiler/AddSessionDomainConstraintPass.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Compiler/AddSessionDomainConstraintPass.php index b1e653a109..461a5ad66d 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Compiler/AddSessionDomainConstraintPass.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Compiler/AddSessionDomainConstraintPass.php @@ -31,7 +31,7 @@ class AddSessionDomainConstraintPass implements CompilerPassInterface } $sessionOptions = $container->getParameter('session.storage.options'); - $domainRegexp = empty($sessionOptions['cookie_domain']) ? '%s' : sprintf('(?:%%s|(?:.+\.)?%s)', preg_quote(trim($sessionOptions['cookie_domain'], '.'))); + $domainRegexp = empty($sessionOptions['cookie_domain']) ? '%%s' : sprintf('(?:%%%%s|(?:.+\.)?%s)', preg_quote(trim($sessionOptions['cookie_domain'], '.'))); if ('auto' === ($sessionOptions['cookie_secure'] ?? null)) { $secureDomainRegexp = sprintf('{^https://%s$}i', $domainRegexp); diff --git a/src/Symfony/Component/Cache/Adapter/PhpArrayAdapter.php b/src/Symfony/Component/Cache/Adapter/PhpArrayAdapter.php index 5f6e99169c..b4f13d1346 100644 --- a/src/Symfony/Component/Cache/Adapter/PhpArrayAdapter.php +++ b/src/Symfony/Component/Cache/Adapter/PhpArrayAdapter.php @@ -61,22 +61,17 @@ class PhpArrayAdapter implements AdapterInterface, CacheInterface, PruneableInte * This adapter takes advantage of how PHP stores arrays in its latest versions. * * @param string $file The PHP file were values are cached - * @param CacheItemPoolInterface $fallbackPool Fallback when opcache is disabled + * @param CacheItemPoolInterface $fallbackPool A pool to fallback on when an item is not hit * * @return CacheItemPoolInterface */ public static function create($file, CacheItemPoolInterface $fallbackPool) { - // Shared memory is available in PHP 7.0+ with OPCache enabled - if (filter_var(ini_get('opcache.enable'), FILTER_VALIDATE_BOOLEAN)) { - if (!$fallbackPool instanceof AdapterInterface) { - $fallbackPool = new ProxyAdapter($fallbackPool); - } - - return new static($file, $fallbackPool); + if (!$fallbackPool instanceof AdapterInterface) { + $fallbackPool = new ProxyAdapter($fallbackPool); } - return $fallbackPool; + return new static($file, $fallbackPool); } /** diff --git a/src/Symfony/Component/Cache/Simple/PhpArrayCache.php b/src/Symfony/Component/Cache/Simple/PhpArrayCache.php index 524df3c8a9..3711f46290 100644 --- a/src/Symfony/Component/Cache/Simple/PhpArrayCache.php +++ b/src/Symfony/Component/Cache/Simple/PhpArrayCache.php @@ -41,18 +41,14 @@ class PhpArrayCache implements Psr16CacheInterface, PruneableInterface, Resettab /** * This adapter takes advantage of how PHP stores arrays in its latest versions. * - * @param string $file The PHP file were values are cached + * @param string $file The PHP file were values are cached + * @param CacheInterface $fallbackPool A pool to fallback on when an item is not hit * * @return Psr16CacheInterface */ public static function create($file, Psr16CacheInterface $fallbackPool) { - // Shared memory is available in PHP 7.0+ with OPCache enabled - if (filter_var(ini_get('opcache.enable'), FILTER_VALIDATE_BOOLEAN)) { - return new static($file, $fallbackPool); - } - - return $fallbackPool; + return new static($file, $fallbackPool); } /** diff --git a/src/Symfony/Component/Cache/Tests/Adapter/PhpArrayAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/PhpArrayAdapterTest.php index 4a5aa82d59..69f334656d 100644 --- a/src/Symfony/Component/Cache/Tests/Adapter/PhpArrayAdapterTest.php +++ b/src/Symfony/Component/Cache/Tests/Adapter/PhpArrayAdapterTest.php @@ -66,6 +66,8 @@ class PhpArrayAdapterTest extends AdapterTestCase protected function tearDown(): void { + $this->createCachePool()->clear(); + if (file_exists(sys_get_temp_dir().'/symfony-cache')) { FilesystemAdapterTest::rmdir(sys_get_temp_dir().'/symfony-cache'); } diff --git a/src/Symfony/Component/Cache/Tests/Adapter/PhpArrayAdapterWithFallbackTest.php b/src/Symfony/Component/Cache/Tests/Adapter/PhpArrayAdapterWithFallbackTest.php index 694b63d89f..a3e998b4b2 100644 --- a/src/Symfony/Component/Cache/Tests/Adapter/PhpArrayAdapterWithFallbackTest.php +++ b/src/Symfony/Component/Cache/Tests/Adapter/PhpArrayAdapterWithFallbackTest.php @@ -38,6 +38,8 @@ class PhpArrayAdapterWithFallbackTest extends AdapterTestCase protected function tearDown(): void { + $this->createCachePool()->clear(); + if (file_exists(sys_get_temp_dir().'/symfony-cache')) { FilesystemAdapterTest::rmdir(sys_get_temp_dir().'/symfony-cache'); } diff --git a/src/Symfony/Component/Cache/Tests/Simple/PhpArrayCacheTest.php b/src/Symfony/Component/Cache/Tests/Simple/PhpArrayCacheTest.php index 36dd116dcd..a504770ac2 100644 --- a/src/Symfony/Component/Cache/Tests/Simple/PhpArrayCacheTest.php +++ b/src/Symfony/Component/Cache/Tests/Simple/PhpArrayCacheTest.php @@ -58,6 +58,8 @@ class PhpArrayCacheTest extends CacheTestCase protected function tearDown(): void { + $this->createSimpleCache()->clear(); + if (file_exists(sys_get_temp_dir().'/symfony-cache')) { FilesystemAdapterTest::rmdir(sys_get_temp_dir().'/symfony-cache'); } diff --git a/src/Symfony/Component/Cache/Tests/Simple/PhpArrayCacheWithFallbackTest.php b/src/Symfony/Component/Cache/Tests/Simple/PhpArrayCacheWithFallbackTest.php index 3afa0ecbcf..84f73012ca 100644 --- a/src/Symfony/Component/Cache/Tests/Simple/PhpArrayCacheWithFallbackTest.php +++ b/src/Symfony/Component/Cache/Tests/Simple/PhpArrayCacheWithFallbackTest.php @@ -45,6 +45,8 @@ class PhpArrayCacheWithFallbackTest extends CacheTestCase protected function tearDown(): void { + $this->createSimpleCache()->clear(); + if (file_exists(sys_get_temp_dir().'/symfony-cache')) { FilesystemAdapterTest::rmdir(sys_get_temp_dir().'/symfony-cache'); } diff --git a/src/Symfony/Component/Cache/Traits/PhpArrayTrait.php b/src/Symfony/Component/Cache/Traits/PhpArrayTrait.php index 89dd8100ba..6e7c72ca7d 100644 --- a/src/Symfony/Component/Cache/Traits/PhpArrayTrait.php +++ b/src/Symfony/Component/Cache/Traits/PhpArrayTrait.php @@ -30,6 +30,8 @@ trait PhpArrayTrait private $keys; private $values; + private static $valuesCache = []; + /** * Store an array of cached values. * @@ -116,6 +118,7 @@ EOF; unset($serialized, $value, $dump); @rename($tmpFile, $this->file); + unset(self::$valuesCache[$this->file]); $this->initialize(); } @@ -133,6 +136,7 @@ EOF; $this->keys = $this->values = []; $cleared = @unlink($this->file) || !file_exists($this->file); + unset(self::$valuesCache[$this->file]); if ($this->pool instanceof AdapterInterface) { return $this->pool->clear($prefix) && $cleared; @@ -146,12 +150,15 @@ EOF; */ private function initialize() { - if (!file_exists($this->file)) { + if (isset(self::$valuesCache[$this->file])) { + $values = self::$valuesCache[$this->file]; + } elseif (!file_exists($this->file)) { $this->keys = $this->values = []; return; + } else { + $values = self::$valuesCache[$this->file] = (include $this->file) ?: [[], []]; } - $values = (include $this->file) ?: [[], []]; if (2 !== \count($values) || !isset($values[0], $values[1])) { $this->keys = $this->values = []; diff --git a/src/Symfony/Component/Config/Resource/ClassExistenceResource.php b/src/Symfony/Component/Config/Resource/ClassExistenceResource.php index ba50c62cd6..77cd8e51aa 100644 --- a/src/Symfony/Component/Config/Resource/ClassExistenceResource.php +++ b/src/Symfony/Component/Config/Resource/ClassExistenceResource.php @@ -37,7 +37,9 @@ class ClassExistenceResource implements SelfCheckingResourceInterface public function __construct(string $resource, bool $exists = null) { $this->resource = $resource; - $this->exists = $exists; + if (null !== $exists) { + $this->exists = [(bool) $exists, null]; + } } /** @@ -65,9 +67,13 @@ class ClassExistenceResource implements SelfCheckingResourceInterface { $loaded = class_exists($this->resource, false) || interface_exists($this->resource, false) || trait_exists($this->resource, false); - if (null !== $exists = &self::$existsCache[(int) (0 >= $timestamp)][$this->resource]) { - $exists = $exists || $loaded; - } elseif (!$exists = $loaded) { + if (null !== $exists = &self::$existsCache[$this->resource]) { + if ($loaded) { + $exists = [true, null]; + } elseif (0 >= $timestamp && !$exists[0] && null !== $exists[1]) { + throw new \ReflectionException($exists[1]); + } + } elseif ([false, null] === $exists = [$loaded, null]) { if (!self::$autoloadLevel++) { spl_autoload_register(__CLASS__.'::throwOnRequiredClass'); } @@ -75,16 +81,19 @@ class ClassExistenceResource implements SelfCheckingResourceInterface self::$autoloadedClass = ltrim($this->resource, '\\'); try { - $exists = class_exists($this->resource) || interface_exists($this->resource, false) || trait_exists($this->resource, false); + $exists[0] = class_exists($this->resource) || interface_exists($this->resource, false) || trait_exists($this->resource, false); } catch (\Exception $e) { + $exists[1] = $e->getMessage(); + try { self::throwOnRequiredClass($this->resource, $e); } catch (\ReflectionException $e) { if (0 >= $timestamp) { - unset(self::$existsCache[1][$this->resource]); throw $e; } } + } catch (\Throwable $e) { + $exists[1] = $e->getMessage(); } finally { self::$autoloadedClass = $autoloadedClass; if (!--self::$autoloadLevel) { @@ -97,7 +106,7 @@ class ClassExistenceResource implements SelfCheckingResourceInterface $this->exists = $exists; } - return $this->exists xor !$exists; + return $this->exists[0] xor !$exists[0]; } /** @@ -112,6 +121,16 @@ class ClassExistenceResource implements SelfCheckingResourceInterface return ['resource', 'exists']; } + /** + * @internal + */ + public function __wakeup() + { + if (\is_bool($this->exists)) { + $this->exists = [$this->exists, null]; + } + } + /** * Throws a reflection exception when the passed class does not exist but is required. * @@ -147,7 +166,17 @@ class ClassExistenceResource implements SelfCheckingResourceInterface throw $previous; } - $e = new \ReflectionException(sprintf('Class "%s" not found while loading "%s".', $class, self::$autoloadedClass), 0, $previous); + $message = sprintf('Class "%s" not found.', $class); + + if (self::$autoloadedClass !== $class) { + $message = substr_replace($message, sprintf(' while loading "%s"', self::$autoloadedClass), -1, 0); + } + + if (null !== $previous) { + $message = $previous->getMessage(); + } + + $e = new \ReflectionException($message, 0, $previous); if (null !== $previous) { throw $e; diff --git a/src/Symfony/Component/Config/Tests/Fixtures/BadFileName.php b/src/Symfony/Component/Config/Tests/Fixtures/BadFileName.php new file mode 100644 index 0000000000..0f79bdd523 --- /dev/null +++ b/src/Symfony/Component/Config/Tests/Fixtures/BadFileName.php @@ -0,0 +1,9 @@ +isFresh(0); } + public function testBadFileName() + { + $this->expectException('ReflectionException'); + $this->expectExceptionMessage('Mismatch between file name and class name.'); + + $res = new ClassExistenceResource(BadFileName::class, false); + $res->isFresh(0); + } + + public function testBadFileNameBis() + { + $this->expectException('ReflectionException'); + $this->expectExceptionMessage('Mismatch between file name and class name.'); + + $res = new ClassExistenceResource(BadFileName::class, false); + $res->isFresh(0); + } + public function testConditionalClass() { $res = new ClassExistenceResource(ConditionalClass::class, false); diff --git a/src/Symfony/Component/Messenger/Middleware/SendMessageMiddleware.php b/src/Symfony/Component/Messenger/Middleware/SendMessageMiddleware.php index 6cfaeb2ef7..149c0c2415 100644 --- a/src/Symfony/Component/Messenger/Middleware/SendMessageMiddleware.php +++ b/src/Symfony/Component/Messenger/Middleware/SendMessageMiddleware.php @@ -35,7 +35,13 @@ class SendMessageMiddleware implements MiddlewareInterface public function __construct(SendersLocatorInterface $sendersLocator, EventDispatcherInterface $eventDispatcher = null) { $this->sendersLocator = $sendersLocator; - $this->eventDispatcher = LegacyEventDispatcherProxy::decorate($eventDispatcher); + + if (null !== $eventDispatcher && class_exists(LegacyEventDispatcherProxy::class)) { + $this->eventDispatcher = LegacyEventDispatcherProxy::decorate($eventDispatcher); + } else { + $this->eventDispatcher = $eventDispatcher; + } + $this->logger = new NullLogger(); } diff --git a/src/Symfony/Component/Messenger/Worker.php b/src/Symfony/Component/Messenger/Worker.php index 546690efa5..1a41009fef 100644 --- a/src/Symfony/Component/Messenger/Worker.php +++ b/src/Symfony/Component/Messenger/Worker.php @@ -47,8 +47,13 @@ class Worker { $this->receivers = $receivers; $this->bus = $bus; - $this->eventDispatcher = LegacyEventDispatcherProxy::decorate($eventDispatcher); $this->logger = $logger; + + if (null !== $eventDispatcher && class_exists(LegacyEventDispatcherProxy::class)) { + $this->eventDispatcher = LegacyEventDispatcherProxy::decorate($eventDispatcher); + } else { + $this->eventDispatcher = $eventDispatcher; + } } /** diff --git a/src/Symfony/Component/Security/Core/Authorization/Voter/TraceableVoter.php b/src/Symfony/Component/Security/Core/Authorization/Voter/TraceableVoter.php index d5fec633ab..ab9e144e9f 100644 --- a/src/Symfony/Component/Security/Core/Authorization/Voter/TraceableVoter.php +++ b/src/Symfony/Component/Security/Core/Authorization/Voter/TraceableVoter.php @@ -31,7 +31,12 @@ class TraceableVoter implements VoterInterface public function __construct(VoterInterface $voter, EventDispatcherInterface $eventDispatcher) { $this->voter = $voter; - $this->eventDispatcher = LegacyEventDispatcherProxy::decorate($eventDispatcher); + + if (class_exists(LegacyEventDispatcherProxy::class)) { + $this->eventDispatcher = LegacyEventDispatcherProxy::decorate($eventDispatcher); + } else { + $this->eventDispatcher = $eventDispatcher; + } } public function vote(TokenInterface $token, $subject, array $attributes): int diff --git a/src/Symfony/Component/Security/Guard/GuardAuthenticatorHandler.php b/src/Symfony/Component/Security/Guard/GuardAuthenticatorHandler.php index 00718e8d75..e406b62c03 100644 --- a/src/Symfony/Component/Security/Guard/GuardAuthenticatorHandler.php +++ b/src/Symfony/Component/Security/Guard/GuardAuthenticatorHandler.php @@ -46,7 +46,13 @@ class GuardAuthenticatorHandler public function __construct(TokenStorageInterface $tokenStorage, EventDispatcherInterface $eventDispatcher = null, array $statelessProviderKeys = []) { $this->tokenStorage = $tokenStorage; - $this->dispatcher = LegacyEventDispatcherProxy::decorate($eventDispatcher); + + if (null !== $eventDispatcher && class_exists(LegacyEventDispatcherProxy::class)) { + $this->dispatcher = LegacyEventDispatcherProxy::decorate($eventDispatcher); + } else { + $this->dispatcher = $eventDispatcher; + } + $this->statelessProviderKeys = $statelessProviderKeys; } diff --git a/src/Symfony/Component/Security/Http/Firewall/AbstractAuthenticationListener.php b/src/Symfony/Component/Security/Http/Firewall/AbstractAuthenticationListener.php index 736c247e7d..8b70a24344 100644 --- a/src/Symfony/Component/Security/Http/Firewall/AbstractAuthenticationListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/AbstractAuthenticationListener.php @@ -93,7 +93,13 @@ abstract class AbstractAuthenticationListener extends AbstractListener implement 'require_previous_session' => true, ], $options); $this->logger = $logger; - $this->dispatcher = LegacyEventDispatcherProxy::decorate($dispatcher); + + if (null !== $dispatcher && class_exists(LegacyEventDispatcherProxy::class)) { + $this->dispatcher = LegacyEventDispatcherProxy::decorate($dispatcher); + } else { + $this->dispatcher = $dispatcher; + } + $this->httpUtils = $httpUtils; } diff --git a/src/Symfony/Component/Security/Http/Firewall/AbstractPreAuthenticatedListener.php b/src/Symfony/Component/Security/Http/Firewall/AbstractPreAuthenticatedListener.php index e14dd1a95a..1d0373bea5 100644 --- a/src/Symfony/Component/Security/Http/Firewall/AbstractPreAuthenticatedListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/AbstractPreAuthenticatedListener.php @@ -52,7 +52,12 @@ abstract class AbstractPreAuthenticatedListener extends AbstractListener impleme $this->authenticationManager = $authenticationManager; $this->providerKey = $providerKey; $this->logger = $logger; - $this->dispatcher = LegacyEventDispatcherProxy::decorate($dispatcher); + + if (null !== $dispatcher && class_exists(LegacyEventDispatcherProxy::class)) { + $this->dispatcher = LegacyEventDispatcherProxy::decorate($dispatcher); + } else { + $this->dispatcher = $dispatcher; + } } /** diff --git a/src/Symfony/Component/Security/Http/Firewall/ContextListener.php b/src/Symfony/Component/Security/Http/Firewall/ContextListener.php index e9e29ab467..2896c35e0e 100644 --- a/src/Symfony/Component/Security/Http/Firewall/ContextListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/ContextListener.php @@ -69,7 +69,13 @@ class ContextListener extends AbstractListener implements ListenerInterface $this->userProviders = $userProviders; $this->sessionKey = '_security_'.$contextKey; $this->logger = $logger; - $this->dispatcher = LegacyEventDispatcherProxy::decorate($dispatcher); + + if (null !== $dispatcher && class_exists(LegacyEventDispatcherProxy::class)) { + $this->dispatcher = LegacyEventDispatcherProxy::decorate($dispatcher); + } else { + $this->dispatcher = $dispatcher; + } + $this->trustResolver = $trustResolver ?: new AuthenticationTrustResolver(AnonymousToken::class, RememberMeToken::class); $this->sessionTrackerEnabler = $sessionTrackerEnabler; } diff --git a/src/Symfony/Component/Security/Http/Firewall/RememberMeListener.php b/src/Symfony/Component/Security/Http/Firewall/RememberMeListener.php index 0cfac54b34..441f70cc2f 100644 --- a/src/Symfony/Component/Security/Http/Firewall/RememberMeListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/RememberMeListener.php @@ -50,7 +50,13 @@ class RememberMeListener extends AbstractListener implements ListenerInterface $this->rememberMeServices = $rememberMeServices; $this->authenticationManager = $authenticationManager; $this->logger = $logger; - $this->dispatcher = LegacyEventDispatcherProxy::decorate($dispatcher); + + if (null !== $dispatcher && class_exists(LegacyEventDispatcherProxy::class)) { + $this->dispatcher = LegacyEventDispatcherProxy::decorate($dispatcher); + } else { + $this->dispatcher = $dispatcher; + } + $this->catchExceptions = $catchExceptions; $this->sessionStrategy = null === $sessionStrategy ? new SessionAuthenticationStrategy(SessionAuthenticationStrategy::MIGRATE) : $sessionStrategy; } diff --git a/src/Symfony/Component/Security/Http/Firewall/SimplePreAuthenticationListener.php b/src/Symfony/Component/Security/Http/Firewall/SimplePreAuthenticationListener.php index 0641d9e45a..bfbda2baad 100644 --- a/src/Symfony/Component/Security/Http/Firewall/SimplePreAuthenticationListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/SimplePreAuthenticationListener.php @@ -65,7 +65,13 @@ class SimplePreAuthenticationListener extends AbstractListener implements Listen $this->providerKey = $providerKey; $this->simpleAuthenticator = $simpleAuthenticator; $this->logger = $logger; - $this->dispatcher = LegacyEventDispatcherProxy::decorate($dispatcher); + + if (null !== $dispatcher && class_exists(LegacyEventDispatcherProxy::class)) { + $this->dispatcher = LegacyEventDispatcherProxy::decorate($dispatcher); + } else { + $this->dispatcher = $dispatcher; + } + $this->trustResolver = $trustResolver ?: new AuthenticationTrustResolver(AnonymousToken::class, RememberMeToken::class); } diff --git a/src/Symfony/Component/Security/Http/Firewall/SwitchUserListener.php b/src/Symfony/Component/Security/Http/Firewall/SwitchUserListener.php index 2263623d75..60660197a4 100644 --- a/src/Symfony/Component/Security/Http/Firewall/SwitchUserListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/SwitchUserListener.php @@ -70,7 +70,13 @@ class SwitchUserListener extends AbstractListener implements ListenerInterface $this->usernameParameter = $usernameParameter; $this->role = $role; $this->logger = $logger; - $this->dispatcher = LegacyEventDispatcherProxy::decorate($dispatcher); + + if (null !== $dispatcher && class_exists(LegacyEventDispatcherProxy::class)) { + $this->dispatcher = LegacyEventDispatcherProxy::decorate($dispatcher); + } else { + $this->dispatcher = $dispatcher; + } + $this->stateless = $stateless; } diff --git a/src/Symfony/Component/Security/Http/Firewall/UsernamePasswordJsonAuthenticationListener.php b/src/Symfony/Component/Security/Http/Firewall/UsernamePasswordJsonAuthenticationListener.php index 50eb405c61..7cb5102e97 100644 --- a/src/Symfony/Component/Security/Http/Firewall/UsernamePasswordJsonAuthenticationListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/UsernamePasswordJsonAuthenticationListener.php @@ -69,7 +69,13 @@ class UsernamePasswordJsonAuthenticationListener extends AbstractListener implem $this->successHandler = $successHandler; $this->failureHandler = $failureHandler; $this->logger = $logger; - $this->eventDispatcher = LegacyEventDispatcherProxy::decorate($eventDispatcher); + + if (null !== $eventDispatcher && class_exists(LegacyEventDispatcherProxy::class)) { + $this->eventDispatcher = LegacyEventDispatcherProxy::decorate($eventDispatcher); + } else { + $this->eventDispatcher = $eventDispatcher; + } + $this->options = array_merge(['username_path' => 'username', 'password_path' => 'password'], $options); $this->propertyAccessor = $propertyAccessor ?: PropertyAccess::createPropertyAccessor(); } diff --git a/src/Symfony/Component/Workflow/Workflow.php b/src/Symfony/Component/Workflow/Workflow.php index 14e57bffdb..6b51b40b96 100644 --- a/src/Symfony/Component/Workflow/Workflow.php +++ b/src/Symfony/Component/Workflow/Workflow.php @@ -43,7 +43,13 @@ class Workflow implements WorkflowInterface { $this->definition = $definition; $this->markingStore = $markingStore ?: new MultipleStateMarkingStore(); - $this->dispatcher = null !== $dispatcher ? LegacyEventDispatcherProxy::decorate($dispatcher) : null; + + if (null !== $dispatcher && class_exists(LegacyEventDispatcherProxy::class)) { + $this->dispatcher = LegacyEventDispatcherProxy::decorate($dispatcher); + } else { + $this->dispatcher = $dispatcher; + } + $this->name = $name; } diff --git a/src/Symfony/Component/Yaml/Inline.php b/src/Symfony/Component/Yaml/Inline.php index 65c3ce61b3..5cdf763e9a 100644 --- a/src/Symfony/Component/Yaml/Inline.php +++ b/src/Symfony/Component/Yaml/Inline.php @@ -617,11 +617,11 @@ class Inline // Optimize for returning strings. // no break case '+' === $scalar[0] || '-' === $scalar[0] || '.' === $scalar[0] || is_numeric($scalar[0]): + if (Parser::preg_match('{^[+-]?[0-9][0-9_]*$}', $scalar)) { + $scalar = str_replace('_', '', (string) $scalar); + } + switch (true) { - case Parser::preg_match('{^[+-]?[0-9][0-9_]*$}', $scalar): - $scalar = str_replace('_', '', (string) $scalar); - // omitting the break / return as integers are handled in the next case - // no break case ctype_digit($scalar): $raw = $scalar; $cast = (int) $scalar; @@ -631,7 +631,7 @@ class Inline $raw = $scalar; $cast = (int) $scalar; - return '0' == $scalar[1] ? octdec($scalar) : (((string) $raw === (string) $cast) ? $cast : $raw); + return '0' == $scalar[1] ? -octdec(substr($scalar, 1)) : (($raw === (string) $cast) ? $cast : $raw); case is_numeric($scalar): case Parser::preg_match(self::getHexRegex(), $scalar): $scalar = str_replace('_', '', $scalar); diff --git a/src/Symfony/Component/Yaml/Tests/InlineTest.php b/src/Symfony/Component/Yaml/Tests/InlineTest.php index 01985ece5b..9b07f8725d 100644 --- a/src/Symfony/Component/Yaml/Tests/InlineTest.php +++ b/src/Symfony/Component/Yaml/Tests/InlineTest.php @@ -720,4 +720,20 @@ class InlineTest extends TestCase $this->expectExceptionMessage("Unexpected end of line, expected one of \",}\n\" at line 1 (near \"{abc: 'def'\")."); Inline::parse("{abc: 'def'"); } + + /** + * @dataProvider getTestsForOctalNumbers + */ + public function testParseOctalNumbers($expected, $yaml) + { + self::assertSame($expected, Inline::parse($yaml)); + } + + public function getTestsForOctalNumbers() + { + return [ + 'positive octal number' => [28, '034'], + 'negative octal number' => [-28, '-034'], + ]; + } }