@@ -195,6 +195,7 @@ public function dump(array $options = [])
195
195
$ this ->singleUsePrivateIds [$ id ] = $ id ;
196
196
}
197
197
}
198
+
198
199
$ this ->container ->getCompiler ()->getServiceReferenceGraph ()->clear ();
199
200
$ checkedNodes = [];
200
201
$ this ->singleUsePrivateIds = array_diff_key ($ this ->singleUsePrivateIds , $ this ->circularReferences );
@@ -409,58 +410,66 @@ private function getProxyDumper(): ProxyDumper
409
410
return $ this ->proxyDumper ;
410
411
}
411
412
412
- private function analyzeCircularReferences (string $ sourceId , array $ edges , array &$ checkedNodes , array & $ currentPath = [], bool $ byConstructor = true )
413
+ private function analyzeCircularReferences (string $ sourceId , array $ edges , array &$ checkedNodes , bool $ byConstructor = true )
413
414
{
414
- $ checkedNodes [$ sourceId ] = true ;
415
- $ currentPath [$ sourceId ] = $ byConstructor ;
415
+ $ newNodes = [];
416
+ $ this ->collectReferences ($ sourceId , $ edges , $ checkedNodes , $ newNodes );
417
+ $ this ->flattendNewReferences ($ checkedNodes , $ newNodes );
418
+
419
+ foreach ($ newNodes as $ newNodeId => $ _ ) {
420
+ if (isset ($ checkedNodes [$ newNodeId ][$ newNodeId ])) {
421
+ $ this ->addCircularReferences ($ newNodeId , $ checkedNodes [$ newNodeId ][$ newNodeId ][0 ], $ byConstructor && $ checkedNodes [$ newNodeId ][$ newNodeId ][1 ]);
422
+ }
423
+ }
424
+ }
416
425
426
+ private function collectReferences (string $ sourceId , array $ edges , array &$ checkedNodes , array &$ newNodes )
427
+ {
428
+ $ checkedNodes [$ sourceId ] = [];
429
+ $ newNodes [$ sourceId ] = [];
417
430
foreach ($ edges as $ edge ) {
418
431
$ node = $ edge ->getDestNode ();
419
432
$ id = $ node ->getId ();
420
-
421
433
if (!$ node ->getValue () instanceof Definition || $ sourceId === $ id || $ edge ->isLazy () || $ edge ->isWeak ()) {
422
- // no-op
423
- } elseif (isset ($ currentPath [$ id ])) {
424
- $ this ->addCircularReferences ($ id , $ currentPath , $ edge ->isReferencedByConstructor ());
425
- } elseif (!isset ($ checkedNodes [$ id ])) {
426
- $ this ->analyzeCircularReferences ($ id , $ node ->getOutEdges (), $ checkedNodes , $ currentPath , $ edge ->isReferencedByConstructor ());
427
- } elseif (isset ($ this ->circularReferences [$ id ])) {
428
- $ this ->connectCircularReferences ($ id , $ currentPath , $ edge ->isReferencedByConstructor ());
434
+ continue ;
429
435
}
430
- }
431
- unset($ currentPath [$ sourceId ]);
432
- }
433
436
434
- private function connectCircularReferences ( string $ sourceId , array & $ currentPath , bool $ byConstructor , array & $ subPath = [])
435
- {
436
- $ currentPath [ $ sourceId ] = $ subPath [ $ sourceId ] = $ byConstructor ;
437
+ if (! isset ( $ checkedNodes [ $ id ])) {
438
+ $ this -> collectReferences ( $ id , $ node -> getOutEdges (), $ checkedNodes , $ newNodes );
439
+ }
437
440
438
- foreach ($ this ->circularReferences [$ sourceId ] as $ id => $ byConstructor ) {
439
- if (isset ($ currentPath [$ id ])) {
440
- $ this ->addCircularReferences ($ id , $ currentPath , $ byConstructor );
441
- } elseif (!isset ($ subPath [$ id ]) && isset ($ this ->circularReferences [$ id ])) {
442
- $ this ->connectCircularReferences ($ id , $ currentPath , $ byConstructor , $ subPath );
441
+ $ checkedNodes [$ sourceId ][$ id ] = [[], $ edge ->isReferencedByConstructor ()];
442
+ if (isset ($ newNodes [$ id ])) {
443
+ $ newNodes [$ id ][$ sourceId ] = true ;
443
444
}
444
445
}
445
- unset($ currentPath [$ sourceId ], $ subPath [$ sourceId ]);
446
446
}
447
447
448
- private function addCircularReferences ( string $ id , array $ currentPath , bool $ byConstructor )
448
+ private function flattendNewReferences ( array & $ checkedNodes , array $ newNodes )
449
449
{
450
- $ currentPath [$ id ] = $ byConstructor ;
451
- $ circularRefs = [];
452
-
453
- foreach (array_reverse ($ currentPath ) as $ parentId => $ v ) {
454
- $ byConstructor = $ byConstructor && $ v ;
455
- $ circularRefs [] = $ parentId ;
456
-
457
- if ($ parentId === $ id ) {
458
- break ;
450
+ $ nodesToFlatten = array_keys ($ newNodes );
451
+ do {
452
+ $ changedNodes = [];
453
+ foreach ($ nodesToFlatten as $ newNodeId ) {
454
+ $ deps = &$ checkedNodes [$ newNodeId ];
455
+ foreach ($ deps as $ id => [$ path , $ depsByConstructor ]) {
456
+ foreach ($ checkedNodes [$ id ] as $ depsId => [$ subPath , $ subDepsByConstructor ]) {
457
+ if (!isset ($ deps [$ depsId ]) || ($ depsByConstructor && $ subDepsByConstructor && !$ deps [$ depsId ][1 ])) {
458
+ $ deps [$ depsId ] = [array_merge ([$ id ], $ subPath ), $ depsByConstructor && $ subDepsByConstructor ];
459
+ $ changedNodes += $ newNodes [$ newNodeId ] ?? [];
460
+ }
461
+ }
462
+ }
459
463
}
460
- }
464
+ $ nodesToFlatten = array_keys ($ changedNodes );
465
+ } while (!empty ($ nodesToFlatten ));
466
+ }
461
467
462
- $ currentId = $ id ;
463
- foreach ($ circularRefs as $ parentId ) {
468
+ private function addCircularReferences (string $ sourceId , array $ currentPath , bool $ byConstructor )
469
+ {
470
+ $ currentId = $ sourceId ;
471
+ array_unshift ($ currentPath , $ currentId );
472
+ foreach (array_reverse ($ currentPath ) as $ parentId ) {
464
473
if (empty ($ this ->circularReferences [$ parentId ][$ currentId ])) {
465
474
$ this ->circularReferences [$ parentId ][$ currentId ] = $ byConstructor ;
466
475
}
0 commit comments