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

Skip to content

Commit bfd7d8f

Browse files
committed
Improve performances in CircualReference detection
1 parent 13af58c commit bfd7d8f

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
@@ -409,58 +409,66 @@ private function getProxyDumper(): ProxyDumper
409409
return $this->proxyDumper;
410410
}
411411

412-
private function analyzeCircularReferences(string $sourceId, array $edges, array &$checkedNodes, array &$currentPath = [], bool $byConstructor = true)
412+
private function analyzeCircularReferences(string $sourceId, array $edges, array &$checkedNodes, bool $byConstructor = true)
413413
{
414-
$checkedNodes[$sourceId] = true;
415-
$currentPath[$sourceId] = $byConstructor;
414+
$newNodes = [];
415+
$this->collectReferences($sourceId, $edges, $checkedNodes, $newNodes);
416+
$this->flattendNewReferences($checkedNodes, $newNodes);
416417

418+
foreach ($newNodes as $newNodeId => $_) {
419+
if (isset($checkedNodes[$newNodeId][$newNodeId])) {
420+
$this->addCircularReferences($newNodeId, $checkedNodes[$newNodeId][$newNodeId][0], $byConstructor && $checkedNodes[$newNodeId][$newNodeId][1]);
421+
}
422+
}
423+
}
424+
425+
private function collectReferences(string $sourceId, array $edges, array &$checkedNodes, array &$newNodes)
426+
{
427+
$checkedNodes[$sourceId] = [];
428+
$newNodes[$sourceId] = [];
417429
foreach ($edges as $edge) {
418430
$node = $edge->getDestNode();
419431
$id = $node->getId();
420-
421432
if (!$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());
433+
continue;
429434
}
430-
}
431-
unset($currentPath[$sourceId]);
432-
}
433435

434-
private function connectCircularReferences(string $sourceId, array &$currentPath, bool $byConstructor, array &$subPath = [])
435-
{
436-
$currentPath[$sourceId] = $subPath[$sourceId] = $byConstructor;
436+
if (!isset($checkedNodes[$id])) {
437+
$this->collectReferences($id, $node->getOutEdges(), $checkedNodes, $newNodes);
438+
}
437439

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);
440+
$checkedNodes[$sourceId][$id] = [[], $edge->isReferencedByConstructor()];
441+
if (isset($newNodes[$id])) {
442+
$newNodes[$id][$sourceId] = true;
443443
}
444444
}
445-
unset($currentPath[$sourceId], $subPath[$sourceId]);
446445
}
447446

448-
private function addCircularReferences(string $id, array $currentPath, bool $byConstructor)
447+
private function flattendNewReferences(array &$checkedNodes, array $newNodes)
449448
{
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;
449+
$nodesToFlatten = array_keys($newNodes);
450+
do {
451+
$changedNodes = [];
452+
foreach ($nodesToFlatten as $newNodeId) {
453+
$deps = &$checkedNodes[$newNodeId];
454+
foreach ($deps as $id => [$path, $depsByConstructor]) {
455+
foreach ($checkedNodes[$id] as $depsId => [$subPath, $subDepsByConstructor]) {
456+
if (!isset($deps[$depsId]) || ($depsByConstructor && $subDepsByConstructor && !$deps[$depsId][1])) {
457+
$deps[$depsId] = [array_merge([$id], $subPath), $depsByConstructor && $subDepsByConstructor];
458+
$changedNodes += $newNodes[$newNodeId] ?? [];
459+
}
460+
}
461+
}
459462
}
460-
}
463+
$nodesToFlatten = array_keys($changedNodes);
464+
} while (!empty($nodesToFlatten));
465+
}
461466

462-
$currentId = $id;
463-
foreach ($circularRefs as $parentId) {
467+
private function addCircularReferences(string $sourceId, array $currentPath, bool $byConstructor)
468+
{
469+
$currentId = $sourceId;
470+
array_unshift($currentPath, $currentId);
471+
foreach (array_reverse($currentPath) as $parentId) {
464472
if (empty($this->circularReferences[$parentId][$currentId])) {
465473
$this->circularReferences[$parentId][$currentId] = $byConstructor;
466474
}

0 commit comments

Comments
 (0)