@@ -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 ($ newNodesas $ newNodeId =>$ _ ) {
412- $ checkedNodes [$ newNodeId ] = [];
413- }
414- continue ;
415- }
416-
417- $ nodesToFlatten =$ newNodes ;
418- do {
419- $ changedNodes = [];
420- foreach ($ nodesToFlattenas $ newNodeId =>$ _ ) {
421- $ deps = &$ checkedNodes [$ newNodeId ];
422- foreach ($ depsas $ 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 ($ newNodesas $ 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 ($ circularas [$ 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 = [];
451425foreach ($ edgesas $ 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 ()) {
455430continue ;
456431 }
457432
458433if (isset ($ path [$ id ])) {
459- $ circular =true ;
434+ $ loop =null ;
435+ $ loopByConstructor =$ edge ->isReferencedByConstructor ();
436+ foreach ($ pathas $ 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 ]);