@@ -195,6 +195,7 @@ public function dump(array $options = [])
195195$ this ->singleUsePrivateIds [$ id ] =$ id ;
196196 }
197197 }
198+
198199$ this ->container ->getCompiler ()->getServiceReferenceGraph ()->clear ();
199200$ checkedNodes = [];
200201$ this ->singleUsePrivateIds =array_diff_key ($ this ->singleUsePrivateIds ,$ this ->circularReferences );
@@ -409,58 +410,66 @@ private function getProxyDumper(): ProxyDumper
409410return $ this ->proxyDumper ;
410411 }
411412
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 )
413414 {
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 ($ newNodesas $ newNodeId =>$ _ ) {
420+ if (isset ($ checkedNodes [$ newNodeId ][$ newNodeId ])) {
421+ $ this ->addCircularReferences ($ newNodeId ,$ checkedNodes [$ newNodeId ][$ newNodeId ][0 ],$ byConstructor &&$ checkedNodes [$ newNodeId ][$ newNodeId ][1 ]);
422+ }
423+ }
424+ }
416425
426+ private function collectReferences (string $ sourceId ,array $ edges ,array &$ checkedNodes ,array &$ newNodes )
427+ {
428+ $ checkedNodes [$ sourceId ] = [];
429+ $ newNodes [$ sourceId ] = [];
417430foreach ($ edgesas $ edge ) {
418431$ node =$ edge ->getDestNode ();
419432$ id =$ node ->getId ();
420-
421433if (!$ 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 ;
429435 }
430- }
431- unset($ currentPath [$ sourceId ]);
432- }
433436
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+ }
437440
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 ;
443444 }
444445 }
445- unset($ currentPath [$ sourceId ],$ subPath [$ sourceId ]);
446446 }
447447
448- private function addCircularReferences ( string $ id ,array $ currentPath , bool $ byConstructor )
448+ private function flattendNewReferences ( array & $ checkedNodes ,array $ newNodes )
449449 {
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 ($ nodesToFlattenas $ newNodeId ) {
454+ $ deps = &$ checkedNodes [$ newNodeId ];
455+ foreach ($ depsas $ 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+ }
459463 }
460- }
464+ $ nodesToFlatten =array_keys ($ changedNodes );
465+ }while (!empty ($ nodesToFlatten ));
466+ }
461467
462- $ currentId =$ id ;
463- foreach ($ circularRefsas $ 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 ) {
464473if (empty ($ this ->circularReferences [$ parentId ][$ currentId ])) {
465474$ this ->circularReferences [$ parentId ][$ currentId ] =$ byConstructor ;
466475 }