Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 97dea49

Browse files
committed
Improve performances in CircualReference detection
1 parent 12578c2 commit 97dea49

File tree

1 file changed

+44
-36
lines changed

1 file changed

+44
-36
lines changed

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

Lines changed: 44 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -432,58 +432,66 @@ private function getProxyDumper(): ProxyDumper
432432
/**
433433
* @param ServiceReferenceGraphEdge[] $edges
434434
*/
435-
private function analyzeCircularReferences(string $sourceId, array $edges, array &$checkedNodes, array &$currentPath = [], bool $byConstructor = true)
435+
private function analyzeCircularReferences(string $sourceId, array $edges, array &$checkedNodes, bool $byConstructor = true)
436436
{
437-
$checkedNodes[$sourceId] = true;
438-
$currentPath[$sourceId] = $byConstructor;
437+
$newNodes = [];
438+
$this->collectReferences($sourceId, $edges, $checkedNodes, $newNodes);
439+
$this->flattendNewReferences($checkedNodes, $newNodes);
439440

441+
foreach ($newNodes as $newNodeId => $_) {
442+
if (isset($checkedNodes[$newNodeId][$newNodeId])) {
443+
$this->addCircularReferences($newNodeId, $checkedNodes[$newNodeId][$newNodeId][0], $byConstructor && $checkedNodes[$newNodeId][$newNodeId][1]);
444+
}
445+
}
446+
}
447+
448+
private function collectReferences(string $sourceId, array $edges, array &$checkedNodes, array &$newNodes)
449+
{
450+
$checkedNodes[$sourceId] = [];
451+
$newNodes[$sourceId] = [];
440452
foreach ($edges as $edge) {
441453
$node = $edge->getDestNode();
442454
$id = $node->getId();
443-
444455
if (!$node->getValue() instanceof Definition || $sourceId === $id || $edge->isLazy() || $edge->isWeak()) {
445-
// no-op
446-
} elseif (isset($currentPath[$id])) {
447-
$this->addCircularReferences($id, $currentPath, $edge->isReferencedByConstructor());
448-
} elseif (!isset($checkedNodes[$id])) {
449-
$this->analyzeCircularReferences($id, $node->getOutEdges(), $checkedNodes, $currentPath, $edge->isReferencedByConstructor());
450-
} elseif (isset($this->circularReferences[$id])) {
451-
$this->connectCircularReferences($id, $currentPath, $edge->isReferencedByConstructor());
456+
continue;
452457
}
453-
}
454-
unset($currentPath[$sourceId]);
455-
}
456458

457-
private function connectCircularReferences(string $sourceId, array &$currentPath, bool $byConstructor, array &$subPath = [])
458-
{
459-
$currentPath[$sourceId] = $subPath[$sourceId] = $byConstructor;
459+
if (!isset($checkedNodes[$id])) {
460+
$this->collectReferences($id, $node->getOutEdges(), $checkedNodes, $newNodes);
461+
}
460462

461-
foreach ($this->circularReferences[$sourceId] as $id => $byConstructor) {
462-
if (isset($currentPath[$id])) {
463-
$this->addCircularReferences($id, $currentPath, $byConstructor);
464-
} elseif (!isset($subPath[$id]) && isset($this->circularReferences[$id])) {
465-
$this->connectCircularReferences($id, $currentPath, $byConstructor, $subPath);
463+
$checkedNodes[$sourceId][$id] = [[], $edge->isReferencedByConstructor()];
464+
if (isset($newNodes[$id])) {
465+
$newNodes[$id][$sourceId] = true;
466466
}
467467
}
468-
unset($currentPath[$sourceId], $subPath[$sourceId]);
469468
}
470469

471-
private function addCircularReferences(string $id, array $currentPath, bool $byConstructor)
470+
private function flattendNewReferences(array &$checkedNodes, array &$newNodes)
472471
{
473-
$currentPath[$id] = $byConstructor;
474-
$circularRefs = [];
475-
476-
foreach (array_reverse($currentPath) as $parentId => $v) {
477-
$byConstructor = $byConstructor && $v;
478-
$circularRefs[] = $parentId;
479-
480-
if ($parentId === $id) {
481-
break;
472+
$nodesToFlatten = array_keys($newNodes);
473+
do {
474+
$changedNodes = [];
475+
foreach ($nodesToFlatten as $newNodeId) {
476+
$deps = &$checkedNodes[$newNodeId];
477+
foreach ($deps as $id => [$path, $depsByConstructor]) {
478+
foreach ($checkedNodes[$id] as $depsId => [$subPath, $subDepsByConstructor]) {
479+
if (!isset($deps[$depsId])) {
480+
$deps[$depsId] = [array_merge([$id], $subPath), $depsByConstructor && $subDepsByConstructor];
481+
$changedNodes += $newNodes[$newNodeId] ?? [];
482+
}
483+
}
484+
}
482485
}
483-
}
486+
$nodesToFlatten = array_keys($changedNodes);
487+
} while (!empty($nodesToFlatten));
488+
}
484489

485-
$currentId = $id;
486-
foreach ($circularRefs as $parentId) {
490+
private function addCircularReferences(string $sourceId, array $currentPath, bool $byConstructor)
491+
{
492+
$currentId = $sourceId;
493+
array_unshift($currentPath, $currentId);
494+
foreach (array_reverse($currentPath) as $parentId) {
487495
if (empty($this->circularReferences[$parentId][$currentId])) {
488496
$this->circularReferences[$parentId][$currentId] = $byConstructor;
489497
}

0 commit comments

Comments
 (0)