@@ -188,6 +188,7 @@ public function dump(array $options = [])
188
188
}
189
189
$ this ->container ->getCompiler ()->getServiceReferenceGraph ()->clear ();
190
190
$ checkedNodes = [];
191
+ $ this ->singleUsePrivateIds = array_diff_key ($ this ->singleUsePrivateIds , $ this ->circularReferences );
191
192
192
193
$ this ->docStar = $ options ['debug ' ] ? '* ' : '' ;
193
194
@@ -343,10 +344,10 @@ private function getProxyDumper(): ProxyDumper
343
344
/**
344
345
* @param ServiceReferenceGraphEdge[] $edges
345
346
*/
346
- private function analyzeCircularReferences (string $ sourceId , array $ edges , array &$ checkedNodes , array &$ currentPath = [])
347
+ private function analyzeCircularReferences (string $ sourceId , array $ edges , array &$ checkedNodes , array &$ currentPath = [], bool $ byConstructor = true )
347
348
{
348
349
$ checkedNodes [$ sourceId ] = true ;
349
- $ currentPath [$ sourceId ] = $ sourceId ;
350
+ $ currentPath [$ sourceId ] = $ byConstructor ;
350
351
351
352
foreach ($ edges as $ edge ) {
352
353
$ node = $ edge ->getDestNode ();
@@ -355,44 +356,52 @@ private function analyzeCircularReferences(string $sourceId, array $edges, array
355
356
if (!$ node ->getValue () instanceof Definition || $ sourceId === $ id || $ edge ->isLazy () || $ edge ->isWeak ()) {
356
357
// no-op
357
358
} elseif (isset ($ currentPath [$ id ])) {
358
- $ currentId = $ id ;
359
- foreach (array_reverse ($ currentPath ) as $ parentId ) {
360
- $ this ->circularReferences [$ parentId ][$ currentId ] = $ currentId ;
361
- if ($ parentId === $ id ) {
362
- break ;
363
- }
364
- $ currentId = $ parentId ;
365
- }
359
+ $ this ->addCircularReferences ($ id , $ currentPath , $ edge ->isReferencedByConstructor ());
366
360
} elseif (!isset ($ checkedNodes [$ id ])) {
367
- $ this ->analyzeCircularReferences ($ id , $ node ->getOutEdges (), $ checkedNodes , $ currentPath );
361
+ $ this ->analyzeCircularReferences ($ id , $ node ->getOutEdges (), $ checkedNodes , $ currentPath, $ edge -> isReferencedByConstructor () );
368
362
} elseif (isset ($ this ->circularReferences [$ id ])) {
369
- $ this ->connectCircularReferences ($ id , $ currentPath );
363
+ $ this ->connectCircularReferences ($ id , $ currentPath, $ edge -> isReferencedByConstructor () );
370
364
}
371
365
}
372
366
unset($ currentPath [$ sourceId ]);
373
367
}
374
368
375
- private function connectCircularReferences (string $ sourceId , array &$ currentPath , array &$ subPath = [])
369
+ private function connectCircularReferences (string $ sourceId , array &$ currentPath , bool $ byConstructor , array &$ subPath = [])
376
370
{
377
- $ subPath [$ sourceId ] = $ sourceId ;
378
- $ currentPath [$ sourceId ] = $ sourceId ;
371
+ $ currentPath [$ sourceId ] = $ subPath [$ sourceId ] = $ byConstructor ;
379
372
380
- foreach ($ this ->circularReferences [$ sourceId ] as $ id ) {
373
+ foreach ($ this ->circularReferences [$ sourceId ] as $ id => $ byConstructor ) {
381
374
if (isset ($ currentPath [$ id ])) {
382
- $ currentId = $ id ;
383
- foreach (array_reverse ($ currentPath ) as $ parentId ) {
384
- $ this ->circularReferences [$ parentId ][$ currentId ] = $ currentId ;
385
- if ($ parentId === $ id ) {
386
- break ;
387
- }
388
- $ currentId = $ parentId ;
389
- }
375
+ $ this ->addCircularReferences ($ id , $ currentPath , $ byConstructor );
390
376
} elseif (!isset ($ subPath [$ id ]) && isset ($ this ->circularReferences [$ id ])) {
391
- $ this ->connectCircularReferences ($ id , $ currentPath , $ subPath );
377
+ $ this ->connectCircularReferences ($ id , $ currentPath , $ byConstructor , $ subPath );
392
378
}
393
379
}
394
- unset($ currentPath [$ sourceId ]);
395
- unset($ subPath [$ sourceId ]);
380
+ unset($ currentPath [$ sourceId ], $ subPath [$ sourceId ]);
381
+ }
382
+
383
+ private function addCircularReferences (string $ id , array $ currentPath , bool $ byConstructor )
384
+ {
385
+ $ currentPath [$ id ] = $ byConstructor ;
386
+ $ circularRefs = [];
387
+
388
+ foreach (array_reverse ($ currentPath ) as $ parentId => $ v ) {
389
+ $ byConstructor = $ byConstructor && $ v ;
390
+ $ circularRefs [] = $ parentId ;
391
+
392
+ if ($ parentId === $ id ) {
393
+ break ;
394
+ }
395
+ }
396
+
397
+ $ currentId = $ id ;
398
+ foreach ($ circularRefs as $ parentId ) {
399
+ if (empty ($ this ->circularReferences [$ parentId ][$ currentId ])) {
400
+ $ this ->circularReferences [$ parentId ][$ currentId ] = $ byConstructor ;
401
+ }
402
+
403
+ $ currentId = $ parentId ;
404
+ }
396
405
}
397
406
398
407
private function collectLineage (string $ class , array &$ lineage )
@@ -683,7 +692,6 @@ private function addService(string $id, Definition $definition): array
683
692
$ autowired = $ definition ->isAutowired () ? ' autowired ' : '' ;
684
693
685
694
if ($ definition ->isLazy ()) {
686
- unset($ this ->circularReferences [$ id ]);
687
695
$ lazyInitialization = '$lazyLoad = true ' ;
688
696
} else {
689
697
$ lazyInitialization = '' ;
@@ -759,12 +767,12 @@ private function addInlineVariables(string $id, Definition $definition, array $a
759
767
760
768
private function addInlineReference (string $ id , Definition $ definition , string $ targetId , bool $ forConstructor ): string
761
769
{
762
- list ($ callCount , $ behavior ) = $ this ->serviceCalls [$ targetId ];
763
-
764
770
while ($ this ->container ->hasAlias ($ targetId )) {
765
771
$ targetId = (string ) $ this ->container ->getAlias ($ targetId );
766
772
}
767
773
774
+ list ($ callCount , $ behavior ) = $ this ->serviceCalls [$ targetId ];
775
+
768
776
if ($ id === $ targetId ) {
769
777
return $ this ->addInlineService ($ id , $ definition , $ definition );
770
778
}
@@ -773,9 +781,13 @@ private function addInlineReference(string $id, Definition $definition, string $
773
781
return '' ;
774
782
}
775
783
776
- $ hasSelfRef = isset ($ this ->circularReferences [$ id ][$ targetId ]);
777
- $ forConstructor = $ forConstructor && !isset ($ this ->definitionVariables [$ definition ]);
778
- $ code = $ hasSelfRef && !$ forConstructor ? $ this ->addInlineService ($ id , $ definition , $ definition ) : '' ;
784
+ $ hasSelfRef = isset ($ this ->circularReferences [$ id ][$ targetId ]) && !isset ($ this ->definitionVariables [$ definition ]);
785
+
786
+ if ($ hasSelfRef && !$ forConstructor && !$ forConstructor = !$ this ->circularReferences [$ id ][$ targetId ]) {
787
+ $ code = $ this ->addInlineService ($ id , $ definition , $ definition );
788
+ } else {
789
+ $ code = '' ;
790
+ }
779
791
780
792
if (isset ($ this ->referenceVariables [$ targetId ]) || (2 > $ callCount && (!$ hasSelfRef || !$ forConstructor ))) {
781
793
return $ code ;
@@ -808,15 +820,23 @@ private function addInlineReference(string $id, Definition $definition, string $
808
820
809
821
private function addInlineService (string $ id , Definition $ definition , Definition $ inlineDef = null , bool $ forConstructor = true ): string
810
822
{
811
- $ isSimpleInstance = $ isRootInstance = null === $ inlineDef ;
823
+ $ code = '' ;
824
+
825
+ if ($ isSimpleInstance = $ isRootInstance = null === $ inlineDef ) {
826
+ foreach ($ this ->serviceCalls as $ targetId => list ($ callCount , $ behavior , $ byConstructor )) {
827
+ if ($ byConstructor && isset ($ this ->circularReferences [$ id ][$ targetId ]) && !$ this ->circularReferences [$ id ][$ targetId ]) {
828
+ $ code .= $ this ->addInlineReference ($ id , $ definition , $ targetId , $ forConstructor );
829
+ }
830
+ }
831
+ }
812
832
813
833
if (isset ($ this ->definitionVariables [$ inlineDef = $ inlineDef ?: $ definition ])) {
814
- return '' ;
834
+ return $ code ;
815
835
}
816
836
817
837
$ arguments = [$ inlineDef ->getArguments (), $ inlineDef ->getFactory ()];
818
838
819
- $ code = $ this ->addInlineVariables ($ id , $ definition , $ arguments , $ forConstructor );
839
+ $ code . = $ this ->addInlineVariables ($ id , $ definition , $ arguments , $ forConstructor );
820
840
821
841
if ($ arguments = array_filter ([$ inlineDef ->getProperties (), $ inlineDef ->getMethodCalls (), $ inlineDef ->getConfigurator ()])) {
822
842
$ isSimpleInstance = false ;
@@ -1475,20 +1495,24 @@ private function getServiceConditionals($value): string
1475
1495
return implode (' && ' , $ conditions );
1476
1496
}
1477
1497
1478
- private function getDefinitionsFromArguments (array $ arguments , \SplObjectStorage $ definitions = null , array &$ calls = []): \SplObjectStorage
1498
+ private function getDefinitionsFromArguments (array $ arguments , \SplObjectStorage $ definitions = null , array &$ calls = [], bool $ byConstructor = null ): \SplObjectStorage
1479
1499
{
1480
1500
if (null === $ definitions ) {
1481
1501
$ definitions = new \SplObjectStorage ();
1482
1502
}
1483
1503
1484
1504
foreach ($ arguments as $ argument ) {
1485
1505
if (\is_array ($ argument )) {
1486
- $ this ->getDefinitionsFromArguments ($ argument , $ definitions , $ calls );
1506
+ $ this ->getDefinitionsFromArguments ($ argument , $ definitions , $ calls, $ byConstructor );
1487
1507
} elseif ($ argument instanceof Reference) {
1488
1508
$ id = (string ) $ argument ;
1489
1509
1510
+ while ($ this ->container ->hasAlias ($ id )) {
1511
+ $ id = (string ) $ this ->container ->getAlias ($ id );
1512
+ }
1513
+
1490
1514
if (!isset ($ calls [$ id ])) {
1491
- $ calls [$ id ] = [0 , $ argument ->getInvalidBehavior ()];
1515
+ $ calls [$ id ] = [0 , $ argument ->getInvalidBehavior (), $ byConstructor ];
1492
1516
} else {
1493
1517
$ calls [$ id ][1 ] = min ($ calls [$ id ][1 ], $ argument ->getInvalidBehavior ());
1494
1518
}
@@ -1500,8 +1524,10 @@ private function getDefinitionsFromArguments(array $arguments, \SplObjectStorage
1500
1524
$ definitions [$ argument ] = 1 + $ definitions [$ argument ];
1501
1525
} else {
1502
1526
$ definitions [$ argument ] = 1 ;
1503
- $ arguments = [$ argument ->getArguments (), $ argument ->getFactory (), $ argument ->getProperties (), $ argument ->getMethodCalls (), $ argument ->getConfigurator ()];
1504
- $ this ->getDefinitionsFromArguments ($ arguments , $ definitions , $ calls );
1527
+ $ arguments = [$ argument ->getArguments (), $ argument ->getFactory ()];
1528
+ $ this ->getDefinitionsFromArguments ($ arguments , $ definitions , $ calls , null === $ byConstructor || $ byConstructor );
1529
+ $ arguments = [$ argument ->getProperties (), $ argument ->getMethodCalls (), $ argument ->getConfigurator ()];
1530
+ $ this ->getDefinitionsFromArguments ($ arguments , $ definitions , $ calls , null !== $ byConstructor && $ byConstructor );
1505
1531
}
1506
1532
}
1507
1533
@@ -1622,6 +1648,11 @@ private function dumpValue($value, bool $interpolate = true): string
1622
1648
return '$ ' .$ value ;
1623
1649
} elseif ($ value instanceof Reference) {
1624
1650
$ id = (string ) $ value ;
1651
+
1652
+ while ($ this ->container ->hasAlias ($ id )) {
1653
+ $ id = (string ) $ this ->container ->getAlias ($ id );
1654
+ }
1655
+
1625
1656
if (null !== $ this ->referenceVariables && isset ($ this ->referenceVariables [$ id ])) {
1626
1657
return $ this ->dumpValue ($ this ->referenceVariables [$ id ], $ interpolate );
1627
1658
}
0 commit comments