@@ -432,58 +432,66 @@ private function getProxyDumper(): ProxyDumper
432
432
/**
433
433
* @param ServiceReferenceGraphEdge[] $edges
434
434
*/
435
- private function analyzeCircularReferences (string $ sourceId , array $ edges , array &$ checkedNodes , array & $ currentPath = [], bool $ byConstructor = true )
435
+ private function analyzeCircularReferences (string $ sourceId , array $ edges , array &$ checkedNodes , bool $ byConstructor = true )
436
436
{
437
- $ checkedNodes [$ sourceId ] = true ;
438
- $ currentPath [$ sourceId ] = $ byConstructor ;
437
+ $ newNodes = [];
438
+ $ this ->collectReferences ($ sourceId , $ edges , $ checkedNodes , $ newNodes );
439
+ $ this ->flattendNewReferences ($ checkedNodes , $ newNodes );
439
440
441
+ foreach ($ newNodes as $ newNodeId => $ _ ) {
442
+ if (isset ($ checkedNodes [$ newNodeId ][$ newNodeId ])) {
443
+ $ this ->addCircularReferences ($ newNodeId , $ checkedNodes [$ newNodeId ][$ newNodeId ][0 ], $ byConstructor && $ checkedNodes [$ newNodeId ][$ newNodeId ][1 ]);
444
+ }
445
+ }
446
+ }
447
+
448
+ private function collectReferences (string $ sourceId , array $ edges , array &$ checkedNodes , array &$ newNodes )
449
+ {
450
+ $ checkedNodes [$ sourceId ] = [];
451
+ $ newNodes [$ sourceId ] = [];
440
452
foreach ($ edges as $ edge ) {
441
453
$ node = $ edge ->getDestNode ();
442
454
$ id = $ node ->getId ();
443
-
444
455
if (!$ node ->getValue () instanceof Definition || $ sourceId === $ id || $ edge ->isLazy () || $ edge ->isWeak ()) {
445
- // no-op
446
- } elseif (isset ($ currentPath [$ id ])) {
447
- $ this ->addCircularReferences ($ id , $ currentPath , $ edge ->isReferencedByConstructor ());
448
- } elseif (!isset ($ checkedNodes [$ id ])) {
449
- $ this ->analyzeCircularReferences ($ id , $ node ->getOutEdges (), $ checkedNodes , $ currentPath , $ edge ->isReferencedByConstructor ());
450
- } elseif (isset ($ this ->circularReferences [$ id ])) {
451
- $ this ->connectCircularReferences ($ id , $ currentPath , $ edge ->isReferencedByConstructor ());
456
+ continue ;
452
457
}
453
- }
454
- unset($ currentPath [$ sourceId ]);
455
- }
456
458
457
- private function connectCircularReferences ( string $ sourceId , array & $ currentPath , bool $ byConstructor , array & $ subPath = [])
458
- {
459
- $ currentPath [ $ sourceId ] = $ subPath [ $ sourceId ] = $ byConstructor ;
459
+ if (! isset ( $ checkedNodes [ $ id ])) {
460
+ $ this -> collectReferences ( $ id , $ node -> getOutEdges (), $ checkedNodes , $ newNodes );
461
+ }
460
462
461
- foreach ($ this ->circularReferences [$ sourceId ] as $ id => $ byConstructor ) {
462
- if (isset ($ currentPath [$ id ])) {
463
- $ this ->addCircularReferences ($ id , $ currentPath , $ byConstructor );
464
- } elseif (!isset ($ subPath [$ id ]) && isset ($ this ->circularReferences [$ id ])) {
465
- $ this ->connectCircularReferences ($ id , $ currentPath , $ byConstructor , $ subPath );
463
+ $ checkedNodes [$ sourceId ][$ id ] = [[], $ edge ->isReferencedByConstructor ()];
464
+ if (isset ($ newNodes [$ id ])) {
465
+ $ newNodes [$ id ][$ sourceId ] = true ;
466
466
}
467
467
}
468
- unset($ currentPath [$ sourceId ], $ subPath [$ sourceId ]);
469
468
}
470
469
471
- private function addCircularReferences ( string $ id , array $ currentPath , bool $ byConstructor )
470
+ private function flattendNewReferences ( array & $ checkedNodes , array & $ newNodes )
472
471
{
473
- $ currentPath [$ id ] = $ byConstructor ;
474
- $ circularRefs = [];
475
-
476
- foreach (array_reverse ($ currentPath ) as $ parentId => $ v ) {
477
- $ byConstructor = $ byConstructor && $ v ;
478
- $ circularRefs [] = $ parentId ;
479
-
480
- if ($ parentId === $ id ) {
481
- break ;
472
+ $ nodesToFlatten = array_keys ($ newNodes );
473
+ do {
474
+ $ changedNodes = [];
475
+ foreach ($ nodesToFlatten as $ newNodeId ) {
476
+ $ deps = &$ checkedNodes [$ newNodeId ];
477
+ foreach ($ deps as $ id => [$ path , $ depsByConstructor ]) {
478
+ foreach ($ checkedNodes [$ id ] as $ depsId => [$ subPath , $ subDepsByConstructor ]) {
479
+ if (!isset ($ deps [$ depsId ])) {
480
+ $ deps [$ depsId ] = [array_merge ([$ id ], $ subPath ), $ depsByConstructor && $ subDepsByConstructor ];
481
+ $ changedNodes += $ newNodes [$ newNodeId ] ?? [];
482
+ }
483
+ }
484
+ }
482
485
}
483
- }
486
+ $ nodesToFlatten = array_keys ($ changedNodes );
487
+ } while (!empty ($ nodesToFlatten ));
488
+ }
484
489
485
- $ currentId = $ id ;
486
- foreach ($ circularRefs as $ parentId ) {
490
+ private function addCircularReferences (string $ sourceId , array $ currentPath , bool $ byConstructor )
491
+ {
492
+ $ currentId = $ sourceId ;
493
+ array_unshift ($ currentPath , $ currentId );
494
+ foreach (array_reverse ($ currentPath ) as $ parentId ) {
487
495
if (empty ($ this ->circularReferences [$ parentId ][$ currentId ])) {
488
496
$ this ->circularReferences [$ parentId ][$ currentId ] = $ byConstructor ;
489
497
}
0 commit comments