diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index 38b552716dfff..f64033f3b7aca 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -453,6 +453,37 @@ public function load(array $configs, ContainerBuilder $container) $container->registerForAutoconfiguration(RouteLoaderInterface::class) ->addTag('routing.route_loader'); + + $this->addClassesToPreload([ + 'Psr\Log\LogLevel', + 'Symfony\Component\Cache\Adapter\ApcuAdapter', + 'Symfony\Component\Cache\Adapter\ArrayAdapter', + 'Symfony\Component\Cache\Adapter\PhpArrayAdapter', + 'Symfony\Component\Cache\Adapter\PhpFilesAdapter', + 'Symfony\Component\Cache\CacheItem', + 'Symfony\Component\DependencyInjection\Argument\RewindableGenerator', + 'Symfony\Component\DependencyInjection\Argument\ServiceLocator', + 'Symfony\Component\DependencyInjection\ContainerAwareInterface', + 'Symfony\Component\DependencyInjection\ContainerAwareTrait', + 'Symfony\Component\Dotenv\Dotenv', + 'Symfony\Component\ErrorHandler\ErrorHandler', + 'Symfony\Component\EventDispatcher\LegacyEventDispatcherProxy', + 'Symfony\Component\HttpFoundation\AcceptHeader', + 'Symfony\Component\HttpFoundation\AcceptHeaderItem', + 'Symfony\Component\HttpFoundation\FileBag', + 'Symfony\Component\HttpFoundation\HeaderBag', + 'Symfony\Component\HttpFoundation\HeaderUtils', + 'Symfony\Component\HttpFoundation\ParameterBag', + 'Symfony\Component\HttpFoundation\ResponseHeaderBag', + 'Symfony\Component\HttpFoundation\ServerBag', + 'Symfony\Component\HttpKernel\Event\ControllerArgumentsEvent', + 'Symfony\Component\HttpKernel\Event\ControllerEvent', + 'Symfony\Component\HttpKernel\Event\TerminateEvent', + 'Symfony\Component\HttpKernel\KernelEvents', + 'Symfony\Component\VarExporter\Internal\Hydrator', + 'Symfony\Component\VarExporter\Internal\Registry', + 'Symfony\Component\WebLink\HttpHeaderSerializer', + ]); } /** @@ -850,6 +881,15 @@ private function registerRouterConfiguration(array $config, ContainerBuilder $co $loader->load('routing.xml'); + $this->addClassesToPreload([ + 'Symfony\Bundle\FrameworkBundle\Routing\RedirectableCompiledUrlMatcher', + 'Symfony\Component\Routing\Annotation\Route', + 'Symfony\Component\Routing\Matcher\CompiledUrlMatcher', + 'Symfony\Component\Routing\Matcher\Dumper\CompiledUrlMatcherTrait', + 'Symfony\Component\Routing\Matcher\RedirectableUrlMatcherInterface', + 'Symfony\Component\Routing\Matcher\UrlMatcher', + ]); + if ($config['utf8']) { $container->getDefinition('routing.loader')->replaceArgument(2, ['utf8' => true]); } @@ -901,6 +941,14 @@ private function registerSessionConfiguration(array $config, ContainerBuilder $c { $loader->load('session.xml'); + $this->addClassesToPreload([ + 'Symfony\Component\HttpFoundation\Session\SessionBagProxy', + 'Symfony\Component\HttpFoundation\Session\Storage\Handler\AbstractSessionHandler', + 'Symfony\Component\HttpFoundation\Session\Storage\Handler\StrictSessionHandler', + 'Symfony\Component\HttpFoundation\Session\Storage\Proxy\AbstractProxy', + 'Symfony\Component\HttpFoundation\Session\Storage\Proxy\SessionHandlerProxy', + ]); + // session storage $container->setAlias('session.storage', $config['storage_id'])->setPrivate(true); $options = ['cache_limiter' => '0']; @@ -1118,6 +1166,10 @@ private function registerTranslatorConfiguration(array $config, ContainerBuilder $loader->load('translation.xml'); + $this->addClassesToPreload([ + 'Symfony\Component\Translation\Formatter\IntlFormatter', + ]); + // Use the "real" translator instead of the identity default $container->setAlias('translator', 'translator.default')->setPublic(true); $container->setAlias('translator.formatter', new Alias($config['formatter'], false)); diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php index b828dfd67abe8..172702e7bd994 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php @@ -161,6 +161,18 @@ public function load(array $configs, ContainerBuilder $container) $container->registerForAutoconfiguration(VoterInterface::class) ->addTag('security.voter'); + + $this->addClassesToPreload([ + 'Symfony\Component\HttpFoundation\RequestMatcher', + 'Symfony\Component\Security\Core\Authorization\ExpressionLanguageProvider', + 'Symfony\Component\Security\Core\Authentication\Provider\AnonymousAuthenticationProvider', + 'Symfony\Component\Security\Core\Authentication\Token\AbstractToken', + 'Symfony\Component\Security\Core\Authentication\Token\AnonymousToken', + 'Symfony\Component\Security\Core\AuthenticationEvents', + 'Symfony\Component\Security\Core\Event\AuthenticationEvent', + 'Symfony\Component\Security\Core\Event\AuthenticationSuccessEvent', + 'Symfony\Component\Security\Http\RememberMe\RememberMeServicesInterface', + ]); } private function createRoleHierarchy(array $config, ContainerBuilder $container) diff --git a/src/Symfony/Bundle/TwigBundle/DependencyInjection/TwigExtension.php b/src/Symfony/Bundle/TwigBundle/DependencyInjection/TwigExtension.php index 9aefb8dbb03fc..15139e8b48614 100644 --- a/src/Symfony/Bundle/TwigBundle/DependencyInjection/TwigExtension.php +++ b/src/Symfony/Bundle/TwigBundle/DependencyInjection/TwigExtension.php @@ -170,6 +170,18 @@ public function load(array $configs, ContainerBuilder $container) $container->removeDefinition('twig.cache_warmer'); $container->removeDefinition('twig.template_cache_warmer'); } + + $this->addClassesToPreload([ + 'Symfony\Component\Stopwatch\Section', + 'Twig\Cache\FilesystemCache', + 'Twig\Extension\CoreExtension', + 'Twig\Extension\EscaperExtension', + 'Twig\Extension\OptimizerExtension', + 'Twig\Extension\StagingExtension', + 'Twig\ExtensionSet', + 'Twig\Template', + 'Twig\TemplateWrapper', + ]); } private function getBundleTemplatePaths(ContainerBuilder $container, array $config) diff --git a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php index c60b3b44f44ca..09a349d95892d 100644 --- a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php +++ b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php @@ -80,6 +80,7 @@ class PhpDumper extends Dumper private $inlinedRequires = []; private $circularReferences = []; private $singleUsePrivateIds = []; + private $preload = []; private $addThrow = false; private $addGetService = false; private $locatedIds = []; @@ -141,6 +142,7 @@ public function dump(array $options = []) 'hot_path_tag' => 'container.hot_path', 'inline_factories_parameter' => 'container.dumper.inline_factories', 'inline_class_loader_parameter' => 'container.dumper.inline_class_loader', + 'preload_classes' => [], 'service_locator_tag' => 'container.service_locator', 'build_time' => time(), ], $options); @@ -225,8 +227,12 @@ public function dump(array $options = []) $proxyClasses = $this->inlineFactories ? $this->generateProxyClasses() : null; + if ($options['preload_classes']) { + $this->preload = array_combine($options['preload_classes'], $options['preload_classes']); + } + $code = - $this->startClass($options['class'], $baseClass, $preload). + $this->startClass($options['class'], $baseClass). $this->addServices($services). $this->addDeprecatedAliases(). $this->addDefaultParametersMethod() @@ -301,7 +307,7 @@ public function dump(array $options = []) $id = hash('crc32', $hash.$time); $this->asFiles = false; - if ($preload && null !== $autoloadFile = $this->getAutoloadFile()) { + if ($this->preload && null !== $autoloadFile = $this->getAutoloadFile()) { $autoloadFile = substr($this->export($autoloadFile), 2, -1); $code[$options['class'].'.preload.php'] = <<preload as $class) { + if ($class && (!(class_exists($class, false) || interface_exists($class, false) || trait_exists($class, false)) || (new \ReflectionClass($class))->isUserDefined())) { + $code[$options['class'].'.preload.php'] .= sprintf("\$classes[] = '%s';\n", $class); + } } $code[$options['class'].'.preload.php'] .= <<<'EOF' @@ -366,6 +374,7 @@ public function dump(array $options = []) $this->circularReferences = []; $this->locatedIds = []; $this->exportedVariables = []; + $this->preload = []; $unusedEnvs = []; foreach ($this->container->getEnvCounters() as $env => $use) { @@ -541,8 +550,13 @@ private function addServiceInclude(string $cId, Definition $definition): string if ($this->inlineRequires && (!$this->isHotPath($definition) || $this->getProxyDumper()->isProxyCandidate($definition))) { $lineage = []; foreach ($this->inlinedDefinitions as $def) { - if (!$def->isDeprecated() && \is_string($class = \is_array($factory = $def->getFactory()) && \is_string($factory[0]) ? $factory[0] : $def->getClass())) { - $this->collectLineage($class, $lineage); + if (!$def->isDeprecated()) { + if ($class = $this->getFactoryClass($def)) { + $this->collectLineage($class, $lineage); + } + if ($class = $def->getClass()) { + $this->collectLineage($class, $lineage); + } } } @@ -551,9 +565,13 @@ private function addServiceInclude(string $cId, Definition $definition): string && ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE !== $behavior && $this->container->has($id) && $this->isTrivialInstance($def = $this->container->findDefinition($id)) - && \is_string($class = \is_array($factory = $def->getFactory()) && \is_string($factory[0]) ? $factory[0] : $def->getClass()) ) { - $this->collectLineage($class, $lineage); + if ($class = $this->getFactoryClass($def)) { + $this->collectLineage($class, $lineage); + } + if ($class = $def->getClass()) { + $this->collectLineage($class, $lineage); + } } } @@ -798,6 +816,15 @@ protected function {$methodName}($lazyInitialization) if ($definition->isDeprecated()) { $code .= sprintf(" @trigger_error(%s, E_USER_DEPRECATED);\n\n", $this->export($definition->getDeprecationMessage($id))); + } else { + foreach ($this->inlinedDefinitions as $def) { + if ($class = $this->getFactoryClass($def)) { + $this->preload[$class] = $class; + } + if ($class = ltrim($def->getClass(), '\\')) { + $this->preload[$class] = $class; + } + } } if ($this->getProxyDumper()->isProxyCandidate($definition)) { @@ -953,7 +980,18 @@ private function addServices(array &$services = null): string $definitions = $this->container->getDefinitions(); ksort($definitions); foreach ($definitions as $id => $definition) { - $services[$id] = $definition->isSynthetic() ? null : $this->addService($id, $definition); + if (!$definition->isSynthetic()) { + $services[$id] = $this->addService($id, $definition); + } else { + $services[$id] = null; + + if ($class = $this->getFactoryClass($definition)) { + $this->preload[$class] = $class; + } + if ($class = ltrim($definition->getClass(), '\\')) { + $this->preload[$class] = $class; + } + } } foreach ($definitions as $id => $definition) { @@ -1054,7 +1092,7 @@ private function addNewInstance(Definition $definition, string $return = '', str return $return.sprintf('new %s(%s)', $this->dumpLiteralClass($this->dumpValue($class)), implode(', ', $arguments)).$tail; } - private function startClass(string $class, string $baseClass, ?array &$preload): string + private function startClass(string $class, string $baseClass): string { $namespaceLine = !$this->asFiles && $this->namespace ? "\nnamespace {$this->namespace};\n" : ''; @@ -1117,7 +1155,7 @@ public function __construct() $code .= $this->addMethodMap(); $code .= $this->asFiles && !$this->inlineFactories ? $this->addFileMap() : ''; $code .= $this->addAliases(); - $code .= $this->addInlineRequires($preload); + $code .= $this->addInlineRequires(); $code .= <<hotPathTag || !$this->inlineRequires) { return ''; @@ -1335,8 +1373,10 @@ private function addInlineRequires(?array &$preload): string $inlinedDefinitions = $this->getDefinitionsFromArguments([$definition]); foreach ($inlinedDefinitions as $def) { - if (\is_string($class = \is_array($factory = $def->getFactory()) && \is_string($factory[0]) ? $factory[0] : $def->getClass())) { - $preload[$class] = $class; + if ($class = $this->getFactoryClass($def)) { + $this->collectLineage($class, $lineage); + } + if ($class = $def->getClass()) { $this->collectLineage($class, $lineage); } } @@ -2058,4 +2098,17 @@ private function getAutoloadFile(): ?string return null; } + + private function getFactoryClass(Definition $definition): ?string + { + while ($definition instanceof Definition && \is_array($factory = $definition->getFactory())) { + if (\is_string($factory[0])) { + return ltrim($factory[0], '\\'); + } + + $definition = $factory[0]; + } + + return null; + } } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services9_as_files.txt b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services9_as_files.txt index 2bbf46c906b95..1845785fb5447 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services9_as_files.txt +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services9_as_files.txt @@ -531,6 +531,24 @@ class ProjectServiceContainer extends Container } } + [ProjectServiceContainer.preload.php] => getParameterBag()->resolveValue($annotatedClasses); $this->kernel->setAnnotatedClassCache($this->expandClasses($annotatedClasses, $existingClasses)); } - - /** - * Expands the given class patterns using a list of existing classes. - * - * @param array $patterns The class patterns to expand - * @param array $classes The existing classes to match against the patterns - */ - private function expandClasses(array $patterns, array $classes): array - { - $expanded = []; - - // Explicit classes declared in the patterns are returned directly - foreach ($patterns as $key => $pattern) { - if ('\\' !== substr($pattern, -1) && false === strpos($pattern, '*')) { - unset($patterns[$key]); - $expanded[] = ltrim($pattern, '\\'); - } - } - - // Match patterns with the classes list - $regexps = $this->patternsToRegexps($patterns); - - foreach ($classes as $class) { - $class = ltrim($class, '\\'); - - if ($this->matchAnyRegexps($class, $regexps)) { - $expanded[] = $class; - } - } - - return array_unique($expanded); - } - - private function getClassesInComposerClassMaps() - { - $classes = []; - - foreach (spl_autoload_functions() as $function) { - if (!\is_array($function)) { - continue; - } - - if ($function[0] instanceof DebugClassLoader || $function[0] instanceof LegacyDebugClassLoader) { - $function = $function[0]->getClassLoader(); - } - - if (\is_array($function) && $function[0] instanceof ClassLoader) { - $classes += array_filter($function[0]->getClassMap()); - } - } - - return array_keys($classes); - } - - private function patternsToRegexps(array $patterns) - { - $regexps = []; - - foreach ($patterns as $pattern) { - // Escape user input - $regex = preg_quote(ltrim($pattern, '\\')); - - // Wildcards * and ** - $regex = strtr($regex, ['\\*\\*' => '.*?', '\\*' => '[^\\\\]*?']); - - // If this class does not end by a slash, anchor the end - if ('\\' !== substr($regex, -1)) { - $regex .= '$'; - } - - $regexps[] = '{^\\\\'.$regex.'}'; - } - - return $regexps; - } - - private function matchAnyRegexps(string $class, array $regexps) - { - $blacklisted = false !== strpos($class, 'Test'); - - foreach ($regexps as $regex) { - if ($blacklisted && false === strpos($regex, 'Test')) { - continue; - } - - if (preg_match($regex, '\\'.$class)) { - return true; - } - } - - return false; - } } diff --git a/src/Symfony/Component/HttpKernel/DependencyInjection/AddClassesToPreloadPass.php b/src/Symfony/Component/HttpKernel/DependencyInjection/AddClassesToPreloadPass.php new file mode 100644 index 0000000000000..26c7bbaae55bc --- /dev/null +++ b/src/Symfony/Component/HttpKernel/DependencyInjection/AddClassesToPreloadPass.php @@ -0,0 +1,57 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpKernel\DependencyInjection; + +use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\HttpKernel\Kernel; + +/** + * Collects the classes to list in the preloading script. + * + * @author Nicolas Grekas + */ +class AddClassesToPreloadPass implements CompilerPassInterface +{ + use ClassMatchingTrait; + + private $kernel; + private $classesToPreload = []; + + public function __construct(Kernel $kernel) + { + $this->kernel = $kernel; + } + + /** + * {@inheritdoc} + */ + public function process(ContainerBuilder $container) + { + $preloadedClasses = $this->kernel->getClassesToPreload(); + foreach ($container->getExtensions() as $extension) { + if ($extension instanceof Extension) { + $preloadedClasses = array_merge($preloadedClasses, $extension->getClassesToPreload()); + } + } + + $existingClasses = $this->getClassesInComposerClassMaps(); + + $preloadedClasses = $container->getParameterBag()->resolveValue($preloadedClasses); + $this->classesToPreload = $this->expandClasses($preloadedClasses, $existingClasses); + } + + public function getClassesToPreload(): array + { + return $this->classesToPreload; + } +} diff --git a/src/Symfony/Component/HttpKernel/DependencyInjection/ClassMatchingTrait.php b/src/Symfony/Component/HttpKernel/DependencyInjection/ClassMatchingTrait.php new file mode 100644 index 0000000000000..4df56768252da --- /dev/null +++ b/src/Symfony/Component/HttpKernel/DependencyInjection/ClassMatchingTrait.php @@ -0,0 +1,114 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpKernel\DependencyInjection; + +use Composer\Autoload\ClassLoader; +use Symfony\Component\Debug\DebugClassLoader as LegacyDebugClassLoader; +use Symfony\Component\ErrorHandler\DebugClassLoader; + +/** + * @author Nicolas Grekas + */ +trait ClassMatchingTrait +{ + /** + * Expands the given class patterns using a list of existing classes. + * + * @param array $patterns The class patterns to expand + * @param array $classes The existing classes to match against the patterns + */ + private function expandClasses(array $patterns, array $classes): array + { + $expanded = []; + + // Explicit classes declared in the patterns are returned directly + foreach ($patterns as $key => $pattern) { + if ('\\' !== substr($pattern, -1) && false === strpos($pattern, '*')) { + unset($patterns[$key]); + $expanded[] = ltrim($pattern, '\\'); + } + } + + // Match patterns with the classes list + $regexps = $this->patternsToRegexps($patterns); + + foreach ($classes as $class) { + $class = ltrim($class, '\\'); + + if ($this->matchAnyRegexps($class, $regexps)) { + $expanded[] = $class; + } + } + + return array_unique($expanded); + } + + private function getClassesInComposerClassMaps(): array + { + $classes = []; + + foreach (spl_autoload_functions() as $function) { + if (!\is_array($function)) { + continue; + } + + if ($function[0] instanceof DebugClassLoader || $function[0] instanceof LegacyDebugClassLoader) { + $function = $function[0]->getClassLoader(); + } + + if (\is_array($function) && $function[0] instanceof ClassLoader) { + $classes += array_filter($function[0]->getClassMap()); + } + } + + return array_keys($classes); + } + + private function patternsToRegexps(array $patterns): array + { + $regexps = []; + + foreach ($patterns as $pattern) { + // Escape user input + $regex = preg_quote(ltrim($pattern, '\\')); + + // Wildcards * and ** + $regex = strtr($regex, ['\\*\\*' => '.*?', '\\*' => '[^\\\\]*?']); + + // If this class does not end by a slash, anchor the end + if ('\\' !== substr($regex, -1)) { + $regex .= '$'; + } + + $regexps[] = '{^\\\\'.$regex.'}'; + } + + return $regexps; + } + + private function matchAnyRegexps(string $class, array $regexps): bool + { + $blacklisted = false !== strpos($class, 'Test'); + + foreach ($regexps as $regex) { + if ($blacklisted && false === strpos($regex, 'Test')) { + continue; + } + + if (preg_match($regex, '\\'.$class)) { + return true; + } + } + + return false; + } +} diff --git a/src/Symfony/Component/HttpKernel/DependencyInjection/Extension.php b/src/Symfony/Component/HttpKernel/DependencyInjection/Extension.php index db376e6d9fb94..7a56e200c6d0d 100644 --- a/src/Symfony/Component/HttpKernel/DependencyInjection/Extension.php +++ b/src/Symfony/Component/HttpKernel/DependencyInjection/Extension.php @@ -21,6 +21,7 @@ abstract class Extension extends BaseExtension { private $annotatedClasses = []; + private $preloadedClasses = []; /** * Gets the annotated classes to cache. @@ -41,4 +42,23 @@ public function addAnnotatedClassesToCompile(array $annotatedClasses) { $this->annotatedClasses = array_merge($this->annotatedClasses, $annotatedClasses); } + + /** + * Gets the classes to list in the preloading script. + */ + public function getClassesToPreload(): array + { + return $this->preloadedClasses; + } + + /** + * Adds classes to list in the preloading script. + * + * When a class is listed, all its parent classes or interfaces are automatically listed too. + * Service classes are also automatically preloaded and don't need to be listed explicitly. + */ + public function addClassesToPreload(array $preloadedClasses): void + { + $this->preloadedClasses = array_merge($this->preloadedClasses, $preloadedClasses); + } } diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index 0f4be74092a7e..6a657457a9227 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -36,6 +36,7 @@ use Symfony\Component\HttpKernel\Bundle\BundleInterface; use Symfony\Component\HttpKernel\Config\FileLocator; use Symfony\Component\HttpKernel\DependencyInjection\AddAnnotatedClassesToCachePass; +use Symfony\Component\HttpKernel\DependencyInjection\AddClassesToPreloadPass; use Symfony\Component\HttpKernel\DependencyInjection\MergeExtensionConfigurationPass; /** @@ -73,6 +74,7 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl private $warmupDir; private $requestStackSize = 0; private $resetServices = false; + private $addClassesToPreloadPass; const VERSION = '4.4.0-DEV'; const VERSION_ID = 40400; @@ -423,6 +425,25 @@ public function getCharset() return 'UTF-8'; } + /** + * Gets the classes to list in the preloading script. + * + * When a class is listed, all its parent classes or interfaces are automatically listed too. + * Service classes are also automatically preloaded and don't need to be listed explicitly. + */ + public function getClassesToPreload(): array + { + $ns = strrpos(\get_class($this), '\\'); + $preload = $ns ? [substr_replace(\get_class($this), '\\**', $ns)] : []; + $preload[] = ConfigCache::class; + + foreach ($this->getBundles() as $bundle) { + $preload[] = \get_class($bundle); + } + + return $preload; + } + /** * Gets the patterns defining the classes to parse and cache for annotations. */ @@ -589,6 +610,7 @@ protected function initializeContainer() $oldContainer = \is_object($oldContainer) ? new \ReflectionClass($oldContainer) : false; $this->dumpContainer($cache, $container, $class, $this->getContainerBaseClass()); + $this->addClassesToPreloadPass = null; $this->container = require $cache->getPath(); $this->container->set('kernel', $this); @@ -680,6 +702,7 @@ protected function buildContainer() } $container->addCompilerPass(new AddAnnotatedClassesToCachePass($this)); + $container->addCompilerPass($this->addClassesToPreloadPass = new AddClassesToPreloadPass($this)); return $container; } @@ -756,6 +779,7 @@ protected function dumpContainer(ConfigCache $cache, ContainerBuilder $container 'as_files' => true, 'debug' => $this->debug, 'build_time' => $container->hasParameter('kernel.container_build_time') ? $container->getParameter('kernel.container_build_time') : time(), + 'preload_classes' => $this->addClassesToPreloadPass ? $this->addClassesToPreloadPass->getClassesToPreload() : [], ]); $rootCode = array_pop($content);