@@ -81,6 +81,7 @@ class PhpDumper extends Dumper
81
81
private $ locatedIds = [];
82
82
private $ serviceLocatorTag ;
83
83
private $ exportedVariables = [];
84
+ private $ baseClass ;
84
85
85
86
/**
86
87
* @var ProxyDumper
@@ -148,11 +149,11 @@ public function dump(array $options = [])
148
149
149
150
if (0 !== strpos ($ baseClass = $ options ['base_class ' ], '\\' ) && 'Container ' !== $ baseClass ) {
150
151
$ baseClass = sprintf ('%s\%s ' , $ options ['namespace ' ] ? '\\' .$ options ['namespace ' ] : '' , $ baseClass );
151
- $ baseClassWithNamespace = $ baseClass ;
152
+ $ this -> baseClass = $ baseClass ;
152
153
} elseif ('Container ' === $ baseClass ) {
153
- $ baseClassWithNamespace = Container::class;
154
+ $ this -> baseClass = Container::class;
154
155
} else {
155
- $ baseClassWithNamespace = $ baseClass ;
156
+ $ this -> baseClass = $ baseClass ;
156
157
}
157
158
158
159
$ this ->initializeMethodNamesMap ('Container ' === $ baseClass ? Container::class : $ baseClass );
@@ -216,7 +217,7 @@ public function dump(array $options = [])
216
217
}
217
218
218
219
$ code =
219
- $ this ->startClass ($ options ['class ' ], $ baseClass , $ baseClassWithNamespace ).
220
+ $ this ->startClass ($ options ['class ' ], $ baseClass , $ preload ).
220
221
$ this ->addServices ($ services ).
221
222
$ this ->addDeprecatedAliases ().
222
223
$ this ->addDefaultParametersMethod ()
@@ -277,6 +278,30 @@ public function dump(array $options = [])
277
278
$ time = $ options ['build_time ' ];
278
279
$ id = hash ('crc32 ' , $ hash .$ time );
279
280
281
+ if ($ preload ) {
282
+ $ code [$ options ['class ' ].'.preload.php ' ] = <<<EOF
283
+ <?php
284
+
285
+ // This file has been auto-generated by the Symfony Dependency Injection Component
286
+ // You can reference it in the "opcache.preload" php.ini setting on PHP >= 7.4 when preloading is desired
287
+
288
+ require dirname(__DIR__, 3).'/vendor/autoload.php';
289
+ require __DIR__.'/Container {$ hash }/ {$ options ['class ' ]}.php';
290
+
291
+
292
+ EOF ;
293
+
294
+ foreach ($ preload as $ file ) {
295
+ $ file = preg_replace ('#^ \\$this->targetDirs\[(\d++)\]# ' , 'dirname(__DIR__, $1) ' , $ file );
296
+
297
+ // Using opcache_compile_file() works, but yields "Can't preload unlinked class [...]" warnings. Why?
298
+ // Using require_once instead fails with "Error Shared memory lock not obtained". Why?
299
+ // Run this command in a skeleton app to give it a try:
300
+ // bin/console c:c && php -dopcache.preload=var/cache/dev/srcApp_KernelDevDebugContainer.preload.php -S localhost:8000 -ddisplay_errors=1 -ddisplay_startup_errors=1
301
+ $ code [$ options ['class ' ].'.preload.php ' ] .= sprintf ("opcache_compile_file(%s); \n" , $ file );
302
+ }
303
+ }
304
+
280
305
$ code [$ options ['class ' ].'.php ' ] = <<<EOF
281
306
<?php
282
307
{$ namespaceLine }
@@ -399,7 +424,7 @@ private function collectLineage($class, array &$lineage)
399
424
if (!$ r = $ this ->container ->getReflectionClass ($ class , false )) {
400
425
return ;
401
426
}
402
- if ($ this ->container instanceof $ class ) {
427
+ if (is_a ( $ class , $ this ->baseClass , true ) ) {
403
428
return ;
404
429
}
405
430
$ file = $ r ->getFileName ();
@@ -474,13 +499,16 @@ private function addServiceInclude(string $cId, Definition $definition): string
474
499
}
475
500
476
501
foreach (array_diff_key (array_flip ($ lineage ), $ this ->inlinedRequires ) as $ file => $ class ) {
502
+ $ file = preg_replace ('#^ \\$this->targetDirs\[(\d++)\]# ' , sprintf ('\dirname(__DIR__, %d + $1) ' , $ this ->asFiles ), $ file );
477
503
$ code .= sprintf (" include_once %s; \n" , $ file );
478
504
}
479
505
}
480
506
481
507
foreach ($ this ->inlinedDefinitions as $ def ) {
482
508
if ($ file = $ def ->getFile ()) {
483
- $ code .= sprintf (" include_once %s; \n" , $ this ->dumpValue ($ file ));
509
+ $ file = $ this ->dumpValue ($ file );
510
+ $ file = preg_replace ('#^ \\$this->targetDirs\[(\d++)\]# ' , sprintf ('\dirname(__DIR__, %d + $1) ' , $ this ->asFiles ), $ file );
511
+ $ code .= sprintf (" include_once %s; \n" , $ file );
484
512
}
485
513
}
486
514
@@ -958,7 +986,7 @@ private function addNewInstance(Definition $definition, string $return = '', str
958
986
return $ return .sprintf ('new %s(%s) ' , $ this ->dumpLiteralClass ($ this ->dumpValue ($ class )), implode (', ' , $ arguments )).$ tail ;
959
987
}
960
988
961
- private function startClass (string $ class , string $ baseClass , string $ baseClassWithNamespace ): string
989
+ private function startClass (string $ class , string $ baseClass , ? array & $ preload ): string
962
990
{
963
991
$ namespaceLine = !$ this ->asFiles && $ this ->namespace ? "\nnamespace {$ this ->namespace }; \n" : '' ;
964
992
@@ -1005,8 +1033,8 @@ public function __construct()
1005
1033
$ code .= " \$this->containerDir = \$containerDir; \n" ;
1006
1034
}
1007
1035
1008
- if (Container::class !== $ baseClassWithNamespace ) {
1009
- $ r = $ this ->container ->getReflectionClass ($ baseClassWithNamespace , false );
1036
+ if (Container::class !== $ this -> baseClass ) {
1037
+ $ r = $ this ->container ->getReflectionClass ($ this -> baseClass , false );
1010
1038
if (null !== $ r
1011
1039
&& (null !== $ constructor = $ r ->getConstructor ())
1012
1040
&& 0 === $ constructor ->getNumberOfRequiredParameters ()
@@ -1026,7 +1054,7 @@ public function __construct()
1026
1054
$ code .= $ this ->addMethodMap ();
1027
1055
$ code .= $ this ->asFiles ? $ this ->addFileMap () : '' ;
1028
1056
$ code .= $ this ->addAliases ();
1029
- $ code .= $ this ->addInlineRequires ();
1057
+ $ code .= $ this ->addInlineRequires ($ preload );
1030
1058
$ code .= <<<EOF
1031
1059
}
1032
1060
@@ -1227,7 +1255,7 @@ protected function {$methodNameAlias}()
1227
1255
return $ code ;
1228
1256
}
1229
1257
1230
- private function addInlineRequires (): string
1258
+ private function addInlineRequires (? array & $ preload ): string
1231
1259
{
1232
1260
if (!$ this ->hotPathTag || !$ this ->inlineRequires ) {
1233
1261
return '' ;
@@ -1251,11 +1279,13 @@ private function addInlineRequires(): string
1251
1279
foreach ($ lineage as $ file ) {
1252
1280
if (!isset ($ this ->inlinedRequires [$ file ])) {
1253
1281
$ this ->inlinedRequires [$ file ] = true ;
1282
+ $ preload [] = $ file ;
1283
+ $ file = preg_replace ('#^ \\$this->targetDirs\[(\d++)\]# ' , sprintf ('\dirname(__DIR__, %d + $1) ' , $ this ->asFiles ), $ file );
1254
1284
$ code .= sprintf ("\n include_once %s; " , $ file );
1255
1285
}
1256
1286
}
1257
1287
1258
- return $ code ? sprintf ("\n \$this->privates['service_container'] = function () {%s \n }; \n" , $ code ) : '' ;
1288
+ return $ code ? sprintf ("\n \$this->privates['service_container'] = static function () {%s \n }; \n" , $ code ) : '' ;
1259
1289
}
1260
1290
1261
1291
private function addDefaultParametersMethod (): string
0 commit comments