10000 [HttpKernel][DI] allow bundles to declare classes that should be prel… · symfony/symfony@90ba34d · GitHub
[go: up one dir, main page]

Skip to content

Commit 90ba34d

Browse files
[HttpKernel][DI] allow bundles to declare classes that should be preloaded
1 parent b00b633 commit 90ba34d

File tree

14 files changed

+408
-109
lines changed

14 files changed

+408
-109
lines changed

src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -453,6 +453,37 @@ public function load(array $configs, ContainerBuilder $container)
453453

454454
$container->registerForAutoconfiguration(RouteLoaderInterface::class)
455455
->addTag('routing.route_loader');
456+
457+
$this->addClassesToPreload([
458+
'Psr\Log\LogLevel',
459+
'Symfony\Component\Cache\Adapter\ApcuAdapter',
460+
'Symfony\Component\Cache\Adapter\ArrayAdapter',
461+
'Symfony\Component\Cache\Adapter\PhpArrayAdapter',
462+
'Symfony\Component\Cache\Adapter\PhpFilesAdapter',
463+
'Symfony\Component\Cache\CacheItem',
464+
'Symfony\Component\DependencyInjection\Argument\RewindableGenerator',
465+
'Symfony\Component\DependencyInjection\Argument\ServiceLocator',
466+
'Symfony\Component\DependencyInjection\ContainerAwareInterface',
467+
'Symfony\Component\DependencyInjection\ContainerAwareTrait',
468+
'Symfony\Component\Dotenv\Dotenv',
469+
'Symfony\Component\ErrorHandler\ErrorHandler',
470+
'Symfony\Component\EventDispatcher\LegacyEventDispatcherProxy',
471+
'Symfony\Component\HttpFoundation\AcceptHeader',
472+
'Symfony\Component\HttpFoundation\AcceptHeaderItem',
473+
'Symfony\Component\HttpFoundation\FileBag',
474+
'Symfony\Component\HttpFoundation\HeaderBag',
475+
'Symfony\Component\HttpFoundation\HeaderUtils',
476+
'Symfony\Component\HttpFoundation\ParameterBag',
477+
'Symfony\Component\HttpFoundation\ResponseHeaderBag',
478+
'Symfony\Component\HttpFoundation\ServerBag',
479+
'Symfony\Component\HttpKernel\Event\ControllerArgumentsEvent',
480+
'Symfony\Component\HttpKernel\Event\ControllerEvent',
481+
'Symfony\Component\HttpKernel\Event\TerminateEvent',
482+
'Symfony\Component\HttpKernel\KernelEvents',
483+
'Symfony\Component\VarExporter\Internal\Hydrator',
484+
'Symfony\Component\VarExporter\Internal\Registry',
485+
'Symfony\Component\WebLink\HttpHeaderSerializer',
486+
]);
456487
}
457488

458489
/**
@@ -850,6 +881,15 @@ private function registerRouterConfiguration(array $config, ContainerBuilder $co
850881

851882
$loader->load('routing.xml');
852883

884+
$this->addClassesToPreload([
885+
'Symfony\Bundle\FrameworkBundle\Routing\RedirectableCompiledUrlMatcher',
886+
'Symfony\Component\Routing\Annotation\Route',
887+
'Symfony\Component\Routing\Matcher\CompiledUrlMatcher',
888+
'Symfony\Component\Routing\Matcher\Dumper\CompiledUrlMatcherTrait',
889+
'Symfony\Component\Routing\Matcher\RedirectableUrlMatcherInterface',
890+
'Symfony\Component\Routing\Matcher\UrlMatcher',
891+
]);
892+
853893
if ($config['utf8']) {
854894
$container->getDefinition('routing.loader')->replaceArgument(2, ['utf8' => true]);
855895
}
@@ -901,6 +941,14 @@ private function registerSessionConfiguration(array $config, ContainerBuilder $c
901941
{
902942
$loader->load('session.xml');
903943

944+
$this->addClassesToPreload([
945+
'Symfony\Component\HttpFoundation\Session\SessionBagProxy',
946+
'Symfony\Component\HttpFoundation\Session\Storage\Handler\AbstractSessionHandler',
947+
'Symfony\Component\HttpFoundation\Session\Storage\Handler\StrictSessionHandler',
948+
'Symfony\Component\HttpFoundation\Session\Storage\Proxy\AbstractProxy',
949+
'Symfony\Component\HttpFoundation\Session\Storage\Proxy\SessionHandlerProxy',
950+
]);
951+
904952
// session storage
905953
$container->setAlias(< EF56 span class=pl-s>'session.storage', $config['storage_id'])->setPrivate(true);
906954
$options = ['cache_limiter' => '0'];
@@ -1118,6 +1166,10 @@ private function registerTranslatorConfiguration(array $config, ContainerBuilder
11181166

11191167
$loader->load('translation.xml');
11201168

1169+
$this->addClassesToPreload([
1170+
'Symfony\Component\Translation\Formatter\IntlFormatter',
1171+
]);
1172+
11211173
// Use the "real" translator instead of the identity default
11221174
$container->setAlias('translator', 'translator.default')->setPublic(true);
11231175
$container->setAlias('translator.formatter', new Alias($config['formatter'], false));

src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,18 @@ public function load(array $configs, ContainerBuilder $container)
161161

162162
$container->registerForAutoconfiguration(VoterInterface::class)
163163
->addTag('security.voter');
164+
165+
$this->addClassesToPreload([
166+
'Symfony\Component\HttpFoundation\RequestMatcher',
167+
'Symfony\Component\Security\Core\Authorization\ExpressionLanguageProvider',
168+
'Symfony\Component\Security\Core\Authentication\Provider\AnonymousAuthenticationProvider',
169+
'Symfony\Component\Security\Core\Authentication\Token\AbstractToken',
170+
'Symfony\Component\Security\Core\Authentication\Token\AnonymousToken',
171+
'Symfony\Component\Security\Core\AuthenticationEvents',
172+
'Symfony\Component\Security\Core\Event\AuthenticationEvent',
173+
'Symfony\Component\Security\Core\Event\AuthenticationSuccessEvent',
174+
'Symfony\Component\Security\Http\RememberMe\RememberMeServicesInterface',
175+
]);
164176
}
165177 1C72

166178
private function createRoleHierarchy(array $config, ContainerBuilder $container)

src/Symfony/Bundle/TwigBundle/DependencyInjection/TwigExtension.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,18 @@ public function load(array $configs, ContainerBuilder $container)
170170
$container->removeDefinition('twig.cache_warmer');
171171
$container->removeDefinition('twig.template_cache_warmer');
172172
}
173+
174+
$this->addClassesToPreload([
175+
'Symfony\Component\Stopwatch\Section',
176+
'Twig\Cache\FilesystemCache',
177+
'Twig\Extension\CoreExtension',
178+
'Twig\Extension\EscaperExtension',
179+
'Twig\Extension\OptimizerExtension',
180+
'Twig\Extension\StagingExtension',
181+
'Twig\ExtensionSet',
182+
'Twig\Template',
183+
'Twig\TemplateWrapper',
184+
]);
173185
}
174186

175187
private function getBundleTemplatePaths(ContainerBuilder $container, array $config)

src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php

Lines changed: 67 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ class PhpDumper extends Dumper
8080
private $inlinedRequires = [];
8181
private $circularReferences = [];
8282
private $singleUsePrivateIds = [];
83+
private $preload = [];
8384
private $addThrow = false;
8485
private $addGetService = false;
8586
private $locatedIds = [];
@@ -141,6 +142,7 @@ public function dump(array $options = [])
141142
'hot_path_tag' => 'container.hot_path',
142143
'inline_factories_parameter' => 'container.dumper.inline_factories',
143144
'inline_class_loader_parameter' => 'container.dumper.inline_class_loader',
145+
'preload_classes' => [],
144146
'service_locator_tag' => 'container.service_locator',
145147
'build_time' => time(),
146148
], $options);
@@ -225,8 +227,12 @@ public function dump(array $options = [])
225227

226228
$proxyClasses = $this->inlineFactories ? $this->generateProxyClasses() : null;
227229

230+
if ($options['preload_classes']) {
231+
$this->preload = array_combine($options['preload_classes'], $options['preload_classes']);
232+
}
233+
228234
$code =
229-
$this->startClass($options['class'], $baseClass, $preload).
235+
$this->startClass($options['class'], $baseClass).
230236
$this->addServices($services).
231237
$this->addDeprecatedAliases().
232238
$this->addDefaultParametersMethod()
@@ -301,7 +307,7 @@ public function dump(array $options = [])
301307
$id = hash('crc32', $hash.$time);
302308
$this->asFiles = false;
303309

304-
if ($preload && null !== $autoloadFile = $this->getAutoloadFile()) {
310+
if ($this->preload && null !== $autoloadFile = $this->getAutoloadFile()) {
305311
$autoloadFile = substr($this->export($autoloadFile), 2, -1);
306312

307313
$code[$options['class'].'.preload.php'] = <<<EOF
@@ -319,8 +325,10 @@ public function dump(array $options = [])
319325
320326
EOF;
321327

322-
foreach ($preload as $class) {
323-
$code[$options['class'].'.preload.php'] .= sprintf("\$classes[] = '%s';\n", $class);
328+
foreach ($this->preload as $class) {
329+
if ($class && (!(class_exists($class, false) || interface_exists($class, false) || trait_exists($class, false)) || (new \ReflectionClass($class))->isUserDefined())) {
330+
$code[$options['class'].'.preload.php'] .= sprintf("\$classes[] = '%s';\n", $class);
331+
}
324332
}
325333

326334
$code[$options['class'].'.preload.php'] .= <<<'EOF'
@@ -366,6 +374,7 @@ public function dump(array $options = [])
366374
$this->circularReferences = [];
367375
$this->locatedIds = [];
368376
$this->exportedVariables = [];
377+
$this->preload = [];
369378

370379
$unusedEnvs = [];
371380
foreach ($this->container->getEnvCounters() as $env => $use) {
@@ -541,8 +550,13 @@ private function addServiceInclude(string $cId, Definition $definition): string
541550
if ($this->inlineRequires && (!$this->isHotPath($definition) || $this->getProxyDumper()->isProxyCandidate($definition))) {
542551
$lineage = [];
543552
foreach ($this->inlinedDefinitions as $def) {
544-
if (!$def->isDeprecated() && \is_string($class = \is_array($factory = $def->getFactory()) && \is_string($factory[0]) ? $factory[0] : $def->getClass())) {
545-
$this->collectLineage($class, $lineage);
553+
if (!$def->isDeprecated()) {
554+
if ($class = $this->getFactoryClass($def)) {
555+
$this->collectLineage($class, $lineage);
556+
}
557+
if ($class = $def->getClass()) {
558+
$this->collectLineage($class, $lineage);
559+
}
546560
}
547561
}
548562

@@ -551,9 +565,13 @@ private function addServiceInclude(string $cId, Definition $definition): string
551565
&& ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE !== $behavior
552566
&& $this->container->has($id)
553567
&& $this->isTrivialInstance($def = $this->container->findDefinition($id))
554-
&& \is_string($class = \is_array($factory = $def->getFactory()) && \is_string($factory[0]) ? $factory[0] : $def->getClass())
555568
) {
556-
$this->collectLineage($class, $lineage);
569+
if ($class = $this->getFactoryClass($def)) {
570+
$this->collectLineage($class, $lineage);
571+
}
572+
if ($class = $def->getClass()) {
573+
$this->collectLineage($class, $lineage);
574+
}
557575
}
558576
}
559577

@@ -798,6 +816,15 @@ protected function {$methodName}($lazyInitialization)
798816

799817
if ($definition->isDeprecated()) {
800818
$code .= sprintf(" @trigger_error(%s, E_USER_DEPRECATED);\n\n", $this->export($definition->getDeprecationMessage($id)));
819+
} else {
820+
foreach ($this->inlinedDefinitions as $def) {
821+
if ($class = $this->getFactoryClass($def)) {
822+
$this->preload[$class] = $class;
823+
}
824+
if ($class = ltrim($def->getClass(), '\\')) {
825+
$this->preload[$class] = $class;
826+
}
827+
}
801828
}
802829

803830
if ($this->getProxyDumper()->isProxyCandidate($definition)) {
@@ -953,7 +980,18 @@ private function addServices(array &$services = null): string
953980
$definitions = $this->container->getDefinitions();
954981
ksort($definitions);
955982
foreach ($definitions as $id => $definition) {
956-
$services[$id] = $definition->isSynthetic() ? null : $this->addService($id, $definition);
983+
if (!$definition->isSynthetic()) {
984+
$services[$id] = $this->addService($id, $definition);
985+
} else {
986+
$services[$id] = null;
987+
988+
if ($class = $this->getFactoryClass($definition)) {
989+
$this->preload[$class] = $class;
990+
}
991+
if ($class = ltrim($definition->getClass(), '\\')) {
992+
$this->preload[$class] = $class;
993+
}
994+
}
957995
}
958996

959997
foreach ($definitions as $id => $definition) {
@@ -1054,7 +1092,7 @@ private function addNewInstance(Definition $definition, string $return = '', str
10541092
return $return.sprintf('new %s(%s)', $this->dumpLiteralClass($this->dumpValue($class)), implode(', ', $arguments)).$tail;
10551093
}
10561094

1057-
private function startClass(string $class, string $baseClass, ?array &$preload): string
1095+
private function startClass(string $class, string $baseClass): string
10581096
{
10591097
$namespaceLine = !$this->asFiles && $this->namespace ? "\nnamespace {$this->namespace};\n" : '';
10601098

@@ -1117,7 +1155,7 @@ public function __construct()
11171155
$code .= $this->addMethodMap();
11181156
$code .= $this->asFiles && !$this->inlineFactories ? $this->addFileMap() : '';
11191157
$code .= $this->addAliases();
1120-
$code .= $this->addInlineRequires($preload);
1158+
$code .= $this->addInlineRequires();
11211159
$code .= <<<EOF
11221160
}
11231161
@@ -1317,7 +1355,7 @@ protected function {$methodNameAlias}()
13171355
return $code;
13181356
}
13191357

1320-
private function addInlineRequires(?array &$preload): string
1358+
private function addInlineRequires(): string
13211359
{
13221360
if (!$this->hotPathTag || !$this->inlineRequires) {
13231361
return '';
@@ -1335,8 +1373,10 @@ private function addInlineRequires(?array &$preload): string
13351373
$inlinedDefinitions = $this->getDefinitionsFromArguments([$definition]);
13361374

13371375
foreach ($inlinedDefinitions as $def) {
1338-
if (\is_string($class = \is_array($factory = $def->getFactory()) && \is_string($factory[0]) ? $factory[0] : $def->getClass())) {
1339-
$preload[$class] = $class;
1376+
if ($class = $this->getFactoryClass($def)) {
1377+
$this->collectLineage($class, $lineage);
1378+
}
1379+
if ($class = $def->getClass()) {
13401380
$this->collectLineage($class, $lineage);
13411381
}
13421382
}
@@ -2058,4 +2098,17 @@ private function getAutoloadFile(): ?string
20582098

20592099
return null;
20602100
}
2101+
2102+
private function getFactoryClass(Definition $definition): ?string
2103+
{
2104+
while ($definition instanceof Definition && \is_array($factory = $definition->getFactory())) {
2105+
if (\is_string($factory[0])) {
2106+
return ltrim($factory[0], '\\');
2107+
}
2108+
2109+
$definition = $factory[0];
2110+
}
2111+
2112+
return null;
2113+
}
20612114
}

src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services9_as_files.txt

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -531,6 +531,24 @@ class ProjectServiceContainer extends Container
531531
}
532532
}
533533

534+
[ProjectServiceContainer.preload.php] => <?php
535+
%A
536+
537+
$classes = [];
538+
$classes[] = 'Bar\FooClass';
539+
$classes[] = 'Baz';
540+
$classes[] = 'ConfClass';
541+
$classes[] = 'Bar';
542+
$classes[] = 'BazClass';
543+
$classes[] = 'Foo';
544+
$classes[] = 'LazyContext';
545+
$classes[] = 'FooBarBaz';
546+
$classes[] = 'FactoryClass';
547+
$classes[] = 'Request';
548+
$classes[] = 'Symfony\Component\DependencyInjection\ContainerInterface';
549+
550+
%A
551+
534552
[ProjectServiceContainer.php] => <?php
535553

536554
// This file has been auto-generated by the Symfony Dependency Injection Component for internal use.

src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services9_inlined_factories.txt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -536,6 +536,16 @@ class ProjectServiceContainer extends Container
536536

537537
$classes = [];
538538
$classes[] = 'Bar\FooClass';
539+
$classes[] = 'Baz';
540+
$classes[] = 'ConfClass';
541+
$classes[] = 'Bar';
542+
$classes[] = 'BazClass';
543+
$classes[] = 'Foo';
544+
$classes[] = 'LazyContext';
545+
$classes[] = 'FooBarBaz';
546+
$classes[] = 'FactoryClass';
547+
$classes[] = 'Request';
548+
$classes[] = 'Symfony\Component\DependencyInjection\ContainerInterface';
539549

540550
%A
541551

src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services9_lazy_inlined_factories.txt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,16 @@ class FooClass_%s extends \Bar\FooClass implements \ProxyManager\Proxy\VirtualPr
165165
%A
166166
}
167167

168+
[ProjectServiceContainer.preload.php] => <?php
169+
%A
170+
171+
$classes = [];
172+
$classes[] = 'Bar\FooClass';
173+
$classes[] = 'Bar\FooLazyClass';
174+
$classes[] = 'Symfony\Component\DependencyInjection\ContainerInterface';
175+
176+
%A
177+
168178
[ProjectServiceContainer.php] => <?php
169179

170180
// This file has been auto-generated by the Symfony Dependency Injection Component for internal use.

src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_non_shared_lazy_as_files.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,15 @@ class ProjectServiceContainer extends Container
8383
}
8484
}
8585

86+
[ProjectServiceContainer.preload.php] => <?php
87+
%A
88+
89+
$classes = [];
90+
$classes[] = 'Bar\FooLazyClass';
91+
$classes[] = 'Symfony\Component\DependencyInjection\ContainerInterface';
92+
93+
%A
94+
8695
[ProjectServiceContainer.php] => <?php
8796

8897
// This file has been auto-generated by the Symfony Dependency Injection Component for internal use.

src/Symfony/Component/HttpKernel/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ CHANGELOG
1414
so you likely do not use those in any app based on the SF Standard or Flex edition.
1515
* Marked all dispatched event classes as `@final`
1616
* Added `ErrorController` to enable the preview and error rendering mechanism
17+
* Added `Kernel::getClassesToPreload()` and `Extension::addClassesToPreload()` to hint PHP 7.4's `opcache.preload`
1718

1819
4.3.0
1920
-----

0 commit comments

Comments
 (0)
0