Skip to content

Commit 136908f

Browse files
committed
Optimize circular collection by removing flattening
1 parent be8fd56 commit 136908f

File tree

2 files changed

+22
-45
lines changed

2 files changed

+22
-45
lines changed

src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php

+18-45
Original file line numberDiff line numberDiff line change
@@ -406,69 +406,42 @@ 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-
}
438-
}
409+
$this->collectCircularReferences($id, $node->getOutEdges(), $checkedNodes);
439410
}
440411

441412
$this->container->getCompiler()->getServiceReferenceGraph()->clear();
442413
$this->singleUsePrivateIds = array_diff_key($this->singleUsePrivateIds, $this->circularReferences);
443414
}
444415

445-
private function collectCircularReferences(string $sourceId, array $edges, array &$checkedNodes, array &$newNodes, array $path = []): bool
416+
private function collectCircularReferences(string $sourceId, array $edges, array &$checkedNodes, array $path = [], bool $byConstructor = true): void
446417
{
447-
$path[$sourceId] = true;
448-
$checkedNodes[$sourceId] = [];
449-
$newNodes[$sourceId] = [];
450-
$circular = false;
418+
$path[$sourceId] = $byConstructor;
419+
$checkedNodes[$sourceId] = true;
451420
foreach ($edges as $edge) {
452421
$node = $edge->getDestNode();
453422
$id = $node->getId();
454-
if (!$node->getValue() instanceof Definition || $sourceId === $id || $edge->isWeak()) {
423+
424+
if (!($definition = $node->getValue()) instanceof Definition || $sourceId === $id || ($edge->isLazy() && ($this->proxyDumper ?? $this->getProxyDumper())->isProxyCandidate($definition)) || $edge->isWeak()) {
455425
continue;
456426
}
457427

458428
if (isset($path[$id])) {
459-
$circular = true;
429+
$loop = null;
430+
$loopByConstructor = $edge->isReferencedByConstructor();
431+
foreach ($path as $k => $pathByConstructor) {
432+
if (null !== $loop) {
433+
$loop[] = $k;
434+
$loopByConstructor = $loopByConstructor && $pathByConstructor;
435+
} elseif ($k === $id) {
436+
$loop = [];
437+
}
438+
}
439+
$this->addCircularReferences($id, $loop, $loopByConstructor);
460440
} 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;
441+
$this->collectCircularReferences($id, $node->getOutEdges(), $checkedNodes, $path, $edge->isReferencedByConstructor());
467442
}
468443
}
469444
unset($path[$sourceId]);
470-
471-
return $circular;
472445
}
473446

474447
private function addCircularReferences(string $sourceId, array $currentPath, bool $byConstructor)

src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php

+4
Original file line numberDiff line numberDiff line change
@@ -1070,6 +1070,10 @@ public function testAlmostCircular($visibility)
10701070

10711071
$manager = $container->get('manager');
10721072
$this->assertEquals(new \stdClass(), $manager);
1073+
$subscriber = $container->get('subscriber');
1074+
$this->assertEquals(new \stdClass(), $subscriber);
1075+
$connection = $container->get('connection');
1076+
$this->assertEquals(new \stdClass(), $connection);
10731077

10741078
$manager = $container->get('manager2');
10751079
$this->assertEquals(new \stdClass(), $manager);

0 commit comments

Comments
 (0)