@@ -63,6 +63,9 @@ class PhpDumper extends Dumper
63
63
private $ usedMethodNames ;
64
64
private $ namespace ;
65
65
private $ asFiles ;
66
+ private $ hotPathTag ;
67
+ private $ inlineRequires ;
68
+ private $ inlinedRequires = array ();
66
69
67
70
/**
68
71
* @var ProxyDumper
@@ -108,16 +111,21 @@ public function setProxyDumper(ProxyDumper $proxyDumper)
108
111
public function dump (array $ options = array ())
109
112
{
110
113
$ this ->targetDirRegex = null ;
114
+ $ this ->inlinedRequires = array ();
111
115
$ options = array_merge (array (
112
116
'class ' => 'ProjectServiceContainer ' ,
113
117
'base_class ' => 'Container ' ,
114
118
'namespace ' => '' ,
115
119
'as_files ' => false ,
116
120
'debug ' => true ,
121
+ 'hot_path_tag ' => null ,
122
+ 'inline_class_loader_parameter ' => 'container.dumper.inline_class_loader ' ,
117
123
), $ options );
118
124
119
125
$ this ->namespace = $ options ['namespace ' ];
120
126
$ this ->asFiles = $ options ['as_files ' ];
127
+ $ this ->hotPathTag = $ options ['hot_path_tag ' ];
128
+ $ this ->inlineRequires = $ this ->container ->hasParameter ($ options ['inline_class_loader_parameter ' ]) && $ this ->container ->getParameter ($ options ['inline_class_loader_parameter ' ]);
121
129
$ this ->initializeMethodNamesMap ($ options ['base_class ' ]);
122
130
123
131
$ this ->docStar = $ options ['debug ' ] ? '* ' : '' ;
@@ -214,6 +222,7 @@ class_alias(Container{$hash}::class, {$options['class']}::class, false);
214
222
}
215
223
216
224
$ this ->targetDirRegex = null ;
225
+ $ this ->inlinedRequires = array ();
217
226
218
227
$ unusedEnvs = array ();
219
228
foreach ($ this ->container ->getEnvCounters () as $ env => $ use ) {
@@ -257,9 +266,13 @@ private function addServiceLocalTempVariables($cId, Definition $definition, arra
257
266
258
267
array_unshift ($ inlinedDefinitions , $ definition );
259
268
269
+ $ collectLineage = $ this ->inlineRequires && !($ this ->hotPathTag && $ definition ->hasTag ($ this ->hotPathTag ));
260
270
$ isNonLazyShared = !$ this ->getProxyDumper ()->isProxyCandidate ($ definition ) && $ definition ->isShared ();
261
- $ calls = $ behavior = array ();
271
+ $ lineage = $ calls = $ behavior = array ();
262
272
foreach ($ inlinedDefinitions as $ iDefinition ) {
273
+ if ($ collectLineage && $ class = is_array ($ factory = $ iDefinition ->getFactory ()) && is_string ($ factory [0 ]) ? $ factory [0 ] : $ iDefinition ->getClass ()) {
274
+ $ this ->collectLineage ($ class , $ lineage );
275
+ }
263
276
$ this ->getServiceCallsFromArguments ($ iDefinition ->getArguments (), $ calls , $ behavior , $ isNonLazyShared );
264
277
$ isPreInstantiation = $ isNonLazyShared && $ iDefinition !== $ definition && !$ this ->hasReference ($ cId , $ iDefinition ->getMethodCalls (), true ) && !$ this ->hasReference ($ cId , $ iDefinition ->getProperties (), true );
265
278
$ this ->getServiceCallsFromArguments ($ iDefinition ->getMethodCalls (), $ calls , $ behavior , $ isPreInstantiation );
@@ -274,6 +287,13 @@ private function addServiceLocalTempVariables($cId, Definition $definition, arra
274
287
continue ;
275
288
}
276
289
290
+ if ($ collectLineage && ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE !== $ behavior [$ id ] && $ this ->container ->has ($ id )
291
+ && $ this ->isTrivialInstance ($ iDefinition = $ this ->container ->findDefinition ($ id ))
292
+ && $ class = is_array ($ factory = $ iDefinition ->getFactory ()) && is_string ($ factory [0 ]) ? $ factory [0 ] : $ iDefinition ->getClass ()
293
+ ) {
294
+ $ this ->collectLineage ($ class , $ lineage );
295
+ }
296
+
277
297
if ($ callCount > 1 ) {
278
298
$ name = $ this ->getNextVariableName ();
279
299
$ this ->referenceVariables [$ id ] = new Variable ($ name );
@@ -300,9 +320,48 @@ private function addServiceLocalTempVariables($cId, Definition $definition, arra
300
320
$ code .= "\n" ;
301
321
}
302
322
323
+ if ($ lineage && $ lineage = array_diff_key (array_flip ($ lineage ), $ this ->inlinedRequires )) {
324
+ $ code = "\n" .$ code ;
325
+
326
+ foreach (array_reverse ($ lineage ) as $ file => $ class ) {
327
+ $ code = sprintf (" require_once %s; \n" , $ file ).$ code ;
328
+ }
329
+ }
330
+
303
331
return $ code ;
304
332
}
305
333
334
+ private function collectLineage ($ class , array &$ lineage )
335
+ {
336
+ if (isset ($ lineage [$ class ])) {
337
+ return ;
338
+ }
339
+ if (!$ r = $ this ->container ->getReflectionClass ($ class )) {
340
+ return ;
341
+ }
342
+ if ($ this ->container instanceof $ class ) {
343
+ return ;
344
+ }
345
+ $ file = $ r ->getFileName ();
346
+ if (!$ file || $ this ->doExport ($ file ) === $ exportedFile = $ this ->export ($ file )) {
347
+ return ;
348
+ }
349
+
350
+ if ($ parent = $ r ->getParentClass ()) {
351
+ $ this ->collectLineage ($ parent ->name , $ lineage );
352
+ }
353
+
354
+ foreach ($ r ->getInterfaces () as $ parent ) {
355
+ $ this ->collectLineage ($ parent ->name , $ lineage );
356
+ }
357
+
358
+ foreach ($ r ->getTraits () as $ parent ) {
359
+ $ this ->collectLineage ($ parent ->name , $ lineage );
360
+ }
361
+
362
+ $ lineage [$ class ] = substr ($ exportedFile , 1 , -1 );
363
+ }
364
+
306
365
private function generateProxyClasses ()
307
366
{
308
367
$ definitions = $ this ->container ->getDefinitions ();
@@ -509,10 +568,15 @@ private function isTrivialInstance(Definition $definition)
509
568
if (!$ v || ($ v instanceof Reference && 'service_container ' === (string ) $ v )) {
510
569
continue ;
511
570
}
571
+ if ($ v instanceof Reference && $ this ->container ->has ($ id = (string ) $ v ) && $ this ->container ->findDefinition ($ id )->isSynthetic ()) {
572
+ continue ;
573
+ }
512
574
if (!is_scalar ($ v ) || $ this ->dumpValue ($ v ) !== $ this ->dumpValue ($ v , false )) {
513
575
return false ;
514
576
}
515
577
}
578
+ } elseif ($ arg instanceof Reference && $ this ->container ->has ($ id = (string ) $ arg ) && $ this ->container ->findDefinition ($ id )->isSynthetic ()) {
579
+ continue ;
516
580
} elseif (!is_scalar ($ arg ) || $ this ->dumpValue ($ arg ) !== $ this ->dumpValue ($ arg , false )) {
517
581
return false ;
518
582
}
@@ -694,7 +758,7 @@ private function addService($id, Definition $definition, &$file = null)
694
758
$ lazyInitialization = '' ;
695
759
}
696
760
697
- $ asFile = $ this ->asFiles && $ definition ->isShared ();
761
+ $ asFile = $ this ->asFiles && $ definition ->isShared () && !( $ this -> hotPathTag && $ definition -> hasTag ( $ this -> hotPathTag )) ;
698
762
$ methodName = $ this ->generateMethodName ($ id );
699
763
if ($ asFile ) {
700
764
$ file = $ methodName .'.php ' ;
@@ -760,7 +824,7 @@ private function addServices()
760
824
$ definitions = $ this ->container ->getDefinitions ();
761
825
ksort ($ definitions );
762
826
foreach ($ definitions as $ id => $ definition ) {
763
- if ($ definition ->isSynthetic () || ($ this ->asFiles && $ definition ->isShared ())) {
827
+ if ($ definition ->isSynthetic () || ($ this ->asFiles && $ definition ->isShared () && !( $ this -> hotPathTag && $ definition -> hasTag ( $ this -> hotPathTag )) )) {
764
828
continue ;
765
829
}
766
830
if ($ definition ->isPublic ()) {
@@ -778,7 +842,7 @@ private function generateServiceFiles()
778
842
$ definitions = $ this ->container ->getDefinitions ();
779
843
ksort ($ definitions );
780
844
foreach ($ definitions as $ id => $ definition ) {
781
- if (!$ definition ->isSynthetic () && $ definition ->isShared ()) {
845
+ if (!$ definition ->isSynthetic () && $ definition ->isShared () && !( $ this -> hotPathTag && $ definition -> hasTag ( $ this -> hotPathTag )) ) {
782
846
$ code = $ this ->addService ($ id , $ definition , $ file );
783
847
yield $ file => $ code ;
784
848
}
@@ -899,6 +963,7 @@ public function __construct()
899
963
$ code .= $ this ->asFiles ? $ this ->addFileMap () : '' ;
900
964
$ code .= $ this ->addPrivateServices ();
901
965
$ code .= $ this ->addAliases ();
966
+ $ code .= $ this ->addInlineRequires ();
902
967
$ code .= <<<'EOF'
903
968
}
904
969
@@ -1050,7 +1115,7 @@ private function addMethodMap()
1050
1115
$ definitions = $ this ->container ->getDefinitions ();
1051
1116
ksort ($ definitions );
1052
1117
foreach ($ definitions as $ id => $ definition ) {
1053
- if (!$ definition ->isSynthetic () && (!$ this ->asFiles || !$ definition ->isShared ())) {
1118
+ if (!$ definition ->isSynthetic () && (!$ this ->asFiles || !$ definition ->isShared () || ( $ this -> hotPathTag && $ definition -> hasTag ( $ this -> hotPathTag )) )) {
1054
1119
$ code .= ' ' .$ this ->export ($ id ).' => ' .$ this ->export ($ this ->generateMethodName ($ id )).", \n" ;
1055
1120
}
1056
1121
}
@@ -1069,7 +1134,7 @@ private function addFileMap()
1069
1134
$ definitions = $ this ->container ->getDefinitions ();
1070
1135
ksort ($ definitions );
1071
1136
foreach ($ definitions as $ id => $ definition ) {
1072
- if (!$ definition ->isSynthetic () && $ definition ->isShared ()) {
1137
+ if (!$ definition ->isSynthetic () && $ definition ->isShared () && !( $ this -> hotPathTag && $ definition -> hasTag ( $ this -> hotPathTag )) ) {
1073
1138
$ code .= sprintf (" %s => __DIR__.'/%s.php', \n" , $ this ->export ($ id ), $ this ->generateMethodName ($ id ));
1074
1139
}
1075
1140
}
@@ -1137,6 +1202,38 @@ private function addAliases()
1137
1202
return $ code ." ); \n" ;
1138
1203
}
1139
1204
1205
+ private function addInlineRequires ()
1206
+ {
1207
+ if (!$ this ->hotPathTag || !$ this ->inlineRequires ) {
1208
+ return '' ;
1209
+ }
1210
+
1211
+ $ lineage = array ();
1212
+
1213
+ foreach ($ this ->container ->findTaggedServiceIds ($ this ->hotPathTag ) as $ id => $ tags ) {
1214
+ $ definition = $ this ->container ->getDefinition ($ id );
1215
+ $ inlinedDefinitions = $ this ->getInlinedDefinitions ($ definition );
1216
+ array_unshift ($ inlinedDefinitions , $ definition );
1217
+
1218
+ foreach ($ inlinedDefinitions as $ iDefinition ) {
1219
+ if ($ class = is_array ($ factory = $ iDefinition ->getFactory ()) && is_string ($ factory [0 ]) ? $ factory [0 ] : $ iDefinition ->getClass ()) {
1220
+ $ this ->collectLineage ($ class , $ lineage );
1221
+ }
1222
+ }
1223
+ }
1224
+
1225
+ $ code = "\n" ;
1226
+
1227
+ foreach ($ lineage as $ file ) {
1228
+ if (!isset ($ this ->inlinedRequires [$ file ])) {
1229
+ $ this ->inlinedRequires [$ file ] = true ;
1230
+ $ code .= sprintf (" require_once %s; \n" , $ file );
1231
+ }
1232
+ }
1233
+
1234
+ return "\n" === $ code ? '' : $ code ;
1235
+ }
1236
+
1140
1237
/**
1141
1238
* Adds default parameters method.
1142
1239
*
@@ -1408,7 +1505,7 @@ private function getServiceCallsFromArguments(array $arguments, array &$calls, a
1408
1505
$ id = (string ) $ argument ;
1409
1506
1410
1507
if (!isset ($ calls [$ id ])) {
1411
- $ calls [$ id ] = (int ) $ isPreInstantiation ;
1508
+ $ calls [$ id ] = (int ) ( $ isPreInstantiation && $ this -> container -> has ( $ id ) && ! $ this -> container -> findDefinition ( $ id )-> isSynthetic ()) ;
1412
1509
}
1413
1510
if (!isset ($ behavior [$ id ])) {
1414
1511
$ behavior [$ id ] = $ argument ->getInvalidBehavior ();
@@ -1746,17 +1843,15 @@ private function getServiceCall($id, Reference $reference = null)
1746
1843
return '$this ' ;
1747
1844
}
1748
1845
1749
- if ($ this ->container ->hasDefinition ($ id )) {
1750
- $ definition = $ this ->container ->getDefinition ($ id );
1751
-
1846
+ if ($ this ->container ->hasDefinition ($ id ) && ($ definition = $ this ->container ->getDefinition ($ id )) && !$ definition ->isSynthetic ()) {
1752
1847
if (null !== $ reference && ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE === $ reference ->getInvalidBehavior ()) {
1753
1848
$ code = 'null ' ;
1754
1849
} elseif ($ this ->isTrivialInstance ($ definition )) {
1755
1850
$ code = substr ($ this ->addNewInstance ($ definition , '' , '' , $ id ), 8 , -2 );
1756
1851
if ($ definition ->isShared ()) {
1757
1852
$ code = sprintf ('$this->services[ \'%s \'] = %s ' , $ id , $ code );
1758
1853
}
1759
- } elseif ($ this ->asFiles && $ definition ->isShared ()) {
1854
+ } elseif ($ this ->asFiles && $ definition ->isShared () && !( $ this -> hotPathTag && $ definition -> hasTag ( $ this -> hotPathTag )) ) {
1760
1855
$ code = sprintf ("\$this->load(__DIR__.'/%s.php') " , $ this ->generateMethodName ($ id ));
1761
1856
} else {
1762
1857
$ code = sprintf ('$this->%s() ' , $ this ->generateMethodName ($ id ));
0 commit comments