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