@@ -82,6 +82,7 @@ class PhpDumper extends Dumper
8282 private $ locatedIds = [];
8383 private $ serviceLocatorTag ;
8484 private $ exportedVariables = [];
85+ private $ baseClass ;
8586
8687 /**
8788 * @var ProxyDumper
@@ -151,11 +152,11 @@ public function dump(array $options = [])
151152
152153 if (0 !== strpos ($ baseClass = $ options ['base_class ' ], '\\' ) && 'Container ' !== $ baseClass ) {
153154 $ baseClass = sprintf ('%s\%s ' , $ options ['namespace ' ] ? '\\' .$ options ['namespace ' ] : '' , $ baseClass );
154- $ baseClassWithNamespace = $ baseClass ;
155+ $ this -> baseClass = $ baseClass ;
155156 } elseif ('Container ' === $ baseClass ) {
156- $ baseClassWithNamespace = Container::class;
157+ $ this -> baseClass = Container::class;
157158 } else {
158- $ baseClassWithNamespace = $ baseClass ;
159+ $ this -> baseClass = $ baseClass ;
159160 }
160161
161162 $ this ->initializeMethodNamesMap ('Container ' === $ baseClass ? Container::class : $ baseClass );
@@ -222,7 +223,7 @@ public function dump(array $options = [])
222223 $ proxyClasses = $ this ->inlineFactories ? $ this ->generateProxyClasses () : null ;
223224
224225 $ code =
225- $ this ->startClass ($ options ['class ' ], $ baseClass , $ baseClassWithNamespace ).
226+ $ this ->startClass ($ options ['class ' ], $ baseClass , $ preload ).
226227 $ this ->addServices ($ services ).
227228 $ this ->addDeprecatedAliases ().
228229 $ this ->addDefaultParametersMethod ()
@@ -296,6 +297,33 @@ public function dump(array $options = [])
296297 $ time = $ options ['build_time ' ];
297298 $ id = hash ('crc32 ' , $ hash .$ time );
298299
300+ if ($ preload ) {
301+ $ code [$ options ['class ' ].'.preload.php ' ] = <<<EOF
302+ <?php
303+
304+ // This file has been auto-generated by the Symfony Dependency Injection Component
305+ // You can reference it in the "opcache.preload" php.ini setting on PHP >= 7.4 when preloading is desired
306+
307+ use Symfony\Component\DependencyInjection\Dumper\Preloader;
308+
309+ require dirname(__DIR__, 3).'/vendor/autoload.php';
310+ require __DIR__.'/Container {$ hash }/ {$ options ['class ' ]}.php';
311+
312+ \$classes = [];
313+
314+ EOF ;
315+
316+ foreach ($ preload as $ class ) {
317+ $ code [$ options ['class ' ].'.preload.php ' ] .= sprintf ("\$classes[] = '%s'; \n" , $ class );
318+ }
319+
320+ $ code [$ options ['class ' ].'.preload.php ' ] .= <<<'EOF'
321+
322+ Preloader::preload($classes);
323+
324+ EOF;
325+ }
326+
299327 $ code [$ options ['class ' ].'.php ' ] = <<<EOF
300328<?php
301329{$ namespaceLine }
@@ -426,14 +454,16 @@ private function collectLineage(string $class, array &$lineage)
426454 if (!$ r = $ this ->container ->getReflectionClass ($ class , false )) {
427455 return ;
428456 }
429- if ($ this ->container instanceof $ class ) {
457+ if (is_a ( $ class , $ this ->baseClass , true ) ) {
430458 return ;
431459 }
432460 $ file = $ r ->getFileName ();
433461 if (!$ file || $ this ->doExport ($ file ) === $ exportedFile = $ this ->export ($ file )) {
434462 return ;
435463 }
436464
465+ $ lineage [$ class ] = substr ($ exportedFile , 1 , -1 );
466+
437467 if ($ parent = $ r ->getParentClass ()) {
438468 $ this ->collectLineage ($ parent ->name , $ lineage );
439469 }
@@ -446,6 +476,7 @@ private function collectLineage(string $class, array &$lineage)
446476 $ this ->collectLineage ($ parent ->name , $ lineage );
447477 }
448478
479+ unset($ lineage [$ class ]);
449480 $ lineage [$ class ] = substr ($ exportedFile , 1 , -1 );
450481 }
451482
@@ -522,13 +553,17 @@ private function addServiceInclude(string $cId, Definition $definition): string
522553 }
523554
524555 foreach (array_diff_key (array_flip ($ lineage ), $ this ->inlinedRequires ) as $ file => $ class ) {
556+ $ file = preg_replace ('#^ \\$this->targetDirs\[(\d++)\]# ' , sprintf ('\dirname(__DIR__, %d + $1) ' , $ this ->asFiles ), $ file );
525557 $ code .= sprintf (" include_once %s; \n" , $ file );
526558 }
527559 }
528560
529561 foreach ($ this ->inlinedDefinitions as $ def ) {
530562 if ($ file = $ def ->getFile ()) {
531- $ code .= sprintf (" include_once %s; \n" , $ this ->dumpValue ($ file ));
563+ $ file = $ this ->dumpValue ($ file );
564+ $ file = '( ' === $ file [0 ] ? substr ($ file , 1 , -1 ) : $ file ;
565+ $ file = preg_replace ('#^ \\$this->targetDirs\[(\d++)\]# ' , sprintf ('\dirname(__DIR__, %d + $1) ' , $ this ->asFiles ), $ file );
566+ $ code .= sprintf (" include_once %s; \n" , $ file );
532567 }
533568 }
534569
@@ -1016,7 +1051,7 @@ private function addNewInstance(Definition $definition, string $return = '', str
10161051 return $ return .sprintf ('new %s(%s) ' , $ this ->dumpLiteralClass ($ this ->dumpValue ($ class )), implode (', ' , $ arguments )).$ tail ;
10171052 }
10181053
1019- private function startClass (string $ class , string $ baseClass , string $ baseClassWithNamespace ): string
1054+ private function startClass (string $ class , string $ baseClass , ? array & $ preload ): string
10201055 {
10211056 $ namespaceLine = !$ this ->asFiles && $ this ->namespace ? "\nnamespace {$ this ->namespace }; \n" : '' ;
10221057
@@ -1064,8 +1099,8 @@ public function __construct()
10641099 $ code .= " \$this->containerDir = \$containerDir; \n" ;
10651100 }
10661101
1067- if (Container::class !== $ baseClassWithNamespace ) {
1068- $ r = $ this ->container ->getReflectionClass ($ baseClassWithNamespace , false );
1102+ if (Container::class !== $ this -> baseClass ) {
1103+ $ r = $ this ->container ->getReflectionClass ($ this -> baseClass , false );
10691104 if (null !== $ r
10701105 && (null !== $ constructor = $ r ->getConstructor ())
10711106 && 0 === $ constructor ->getNumberOfRequiredParameters ()
@@ -1085,7 +1120,7 @@ public function __construct()
10851120 $ code .= $ this ->addMethodMap ();
10861121 $ code .= $ this ->asFiles && !$ this ->inlineFactories ? $ this ->addFileMap () : '' ;
10871122 $ code .= $ this ->addAliases ();
1088- $ code .= $ this ->addInlineRequires ();
1123+ $ code .= $ this ->addInlineRequires ($ preload );
10891124 $ code .= <<<EOF
10901125 }
10911126
@@ -1285,7 +1320,7 @@ protected function {$methodNameAlias}()
12851320 return $ code ;
12861321 }
12871322
1288- private function addInlineRequires (): string
1323+ private function addInlineRequires (? array & $ preload ): string
12891324 {
12901325 if (!$ this ->hotPathTag || !$ this ->inlineRequires ) {
12911326 return '' ;
@@ -1304,6 +1339,7 @@ private function addInlineRequires(): string
13041339
13051340 foreach ($ inlinedDefinitions as $ def ) {
13061341 if (\is_string ($ class = \is_array ($ factory = $ def ->getFactory ()) && \is_string ($ factory [0 ]) ? $ factory [0 ] : $ def ->getClass ())) {
1342+ $ preload [$ class ] = $ class ;
13071343 $ this ->collectLineage ($ class , $ lineage );
13081344 }
13091345 }
@@ -1314,11 +1350,12 @@ private function addInlineRequires(): string
13141350 foreach ($ lineage as $ file ) {
13151351 if (!isset ($ this ->inlinedRequires [$ file ])) {
13161352 $ this ->inlinedRequires [$ file ] = true ;
1353+ $ file = preg_replace ('#^ \\$this->targetDirs\[(\d++)\]# ' , sprintf ('\dirname(__DIR__, %d + $1) ' , $ this ->asFiles ), $ file );
13171354 $ code .= sprintf ("\n include_once %s; " , $ file );
13181355 }
13191356 }
13201357
1321- return $ code ? sprintf ("\n \$this->privates['service_container'] = function () {%s \n }; \n" , $ code ) : '' ;
1358+ return $ code ? sprintf ("\n \$this->privates['service_container'] = static function () {%s \n }; \n" , $ code ) : '' ;
13221359 }
13231360
13241361 private function addDefaultParametersMethod (): string
0 commit comments