@@ -406,64 +406,44 @@ private function analyzeReferences()
406406 $ this ->singleUsePrivateIds [$ id ] = $ id ;
407407 }
408408
409- $ newNodes = [];
410- if (!$ this ->collectCircularReferences ($ id , $ node ->getOutEdges (), $ checkedNodes , $ newNodes )) {
411- foreach ($ newNodes as $ newNodeId => $ _ ) {
412- $ checkedNodes [$ newNodeId ] = [];
413- }
414- continue ;
415- }
416-
417- $ nodesToFlatten = $ newNodes ;
418- do {
419- $ changedNodes = [];
420- foreach ($ nodesToFlatten as $ newNodeId => $ _ ) {
421- $ deps = &$ checkedNodes [$ newNodeId ];
422- foreach ($ deps as $ id => [$ path , $ depsByConstructor ]) {
423- foreach ($ checkedNodes [$ id ] as $ depsId => [$ subPath , $ subDepsByConstructor ]) {
424- if (!isset ($ deps [$ depsId ]) || ($ depsByConstructor && $ subDepsByConstructor && !$ deps [$ depsId ][1 ])) {
425- array_unshift ($ subPath , $ id );
426- $ deps [$ depsId ] = [$ subPath , $ depsByConstructor && $ subDepsByConstructor ];
427- $ changedNodes += $ newNodes [$ newNodeId ] ?? [];
428- }
429- }
430- }
431- }
432- } while ($ nodesToFlatten = $ changedNodes );
433-
434- foreach ($ newNodes as $ newNodeId => $ _ ) {
435- if (null !== $ n = $ checkedNodes [$ newNodeId ][$ newNodeId ] ?? null ) {
436- $ this ->addCircularReferences ($ newNodeId , $ n [0 ], $ n [1 ]);
437- }
409+ $ circular = $ this ->collectCircularReferences ($ id , $ node ->getOutEdges (), $ checkedNodes );
410+ foreach ($ circular as [$ loop , $ byConstructor ]) {
411+ $ sourceId = array_shift ($ loop );
412+ $ this ->addCircularReferences ($ sourceId , $ loop , $ byConstructor );
438413 }
439414 }
440415
441416 $ this ->container ->getCompiler ()->getServiceReferenceGraph ()->clear ();
442417 $ this ->singleUsePrivateIds = array_diff_key ($ this ->singleUsePrivateIds , $ this ->circularReferences );
443418 }
444419
445- private function collectCircularReferences (string $ sourceId , array $ edges , array &$ checkedNodes , array & $ newNodes , array $ path = [] ): bool
420+ private function collectCircularReferences (string $ sourceId , array $ edges , array &$ checkedNodes , array $ path = [], bool $ byConstructor = true ): array
446421 {
447- $ path [$ sourceId ] = true ;
448- $ checkedNodes [$ sourceId ] = [];
449- $ newNodes [$ sourceId ] = [];
450- $ circular = false ;
422+ $ path [$ sourceId ] = $ byConstructor ;
423+ $ checkedNodes [$ sourceId ] = true ;
424+ $ circular = [];
451425 foreach ($ edges as $ edge ) {
452426 $ node = $ edge ->getDestNode ();
453427 $ id = $ node ->getId ();
454- if (!$ node ->getValue () instanceof Definition || $ sourceId === $ id || $ edge ->isWeak ()) {
428+
429+ if (!($ definition = $ node ->getValue ()) instanceof Definition || $ sourceId === $ id || ($ edge ->isLazy () && ($ this ->proxyDumper ?? $ this ->getProxyDumper ())->isProxyCandidate ($ definition )) || $ edge ->isWeak ()) {
455430 continue ;
456431 }
457432
458433 if (isset ($ path [$ id ])) {
459- $ circular = true ;
434+ $ loop = null ;
435+ $ loopByConstructor = $ edge ->isReferencedByConstructor ();
436+ foreach ($ path as $ k => $ pathByConstructor ) {
437+ if (null !== $ loop ) {
438+ $ loop [] = $ k ;
439+ $ loopByConstructor = $ loopByConstructor && $ pathByConstructor ;
440+ } elseif ($ k === $ id ) {
441+ $ loop = [$ k ];
442+ }
443+ }
444+ $ circular [] = [$ loop , $ loopByConstructor ];
460445 } elseif (!isset ($ checkedNodes [$ id ])) {
461- $ circular = $ this ->collectCircularReferences ($ id , $ node ->getOutEdges (), $ checkedNodes , $ newNodes , $ path ) || $ circular ;
462- }
463-
464- $ checkedNodes [$ sourceId ][$ id ] = [[], $ edge ->isReferencedByConstructor ()];
465- if (isset ($ newNodes [$ id ])) {
466- $ newNodes [$ id ][$ sourceId ] = true ;
446+ $ circular = array_merge ($ circular , $ this ->collectCircularReferences ($ id , $ node ->getOutEdges (), $ checkedNodes , $ path , $ edge ->isReferencedByConstructor ()));
467447 }
468448 }
469449 unset($ path [$ sourceId ]);
0 commit comments