Skip to content

Commit fc6df71

Browse files
Merge branch '4.4' into 5.1
* 4.4: [Process] Dont test TTY if there is no TTY support Fixing some Mongolian translating the validators for european portuguese language Fix CI Update validators.he.xlf Update security.he.xlf Update validators.he.xlf Improve performances in CircualReference detection [PHPUnitBridge] Fixed crash on Windows with PHP 8 Fix session called initized several time
2 parents d859f4a + 6883d61 commit fc6df71

File tree

1 file changed

+71
-58
lines changed

1 file changed

+71
-58
lines changed

Dumper/PhpDumper.php

Lines changed: 71 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -185,25 +185,7 @@ public function dump(array $options = [])
185185
}
186186
}
187187

188-
(new AnalyzeServiceReferencesPass(false, !$this->getProxyDumper() instanceof NullDumper))->process($this->container);
189-
$checkedNodes = [];
190-
$this->circularReferences = [];
191-
$this->singleUsePrivateIds = [];
192-
foreach ($this->container->getCompiler()->getServiceReferenceGraph()->getNodes() as $id => $node) {
193-
if (!$node->getValue() instanceof Definition) {
194-
continue;
195-
}
196-
if (!isset($checkedNodes[$id])) {
197-
$this->analyzeCircularReferences($id, $node->getOutEdges(), $checkedNodes);
198-
}
199-
if ($this->isSingleUsePrivateNode($node)) {
200-
$this->singleUsePrivateIds[$id] = $id;
201-
}
202-
}
203-
$this->container->getCompiler()->getServiceReferenceGraph()->clear();
204-
$checkedNodes = [];
205-
$this->singleUsePrivateIds = array_diff_key($this->singleUsePrivateIds, $this->circularReferences);
206-
188+
$this->analyzeReferences();
207189
$this->docStar = $options['debug'] ? '*' : '';
208190

209191
if (!empty($options['file']) && is_dir($dir = \dirname($options['file']))) {
@@ -429,61 +411,92 @@ private function getProxyDumper(): ProxyDumper
429411
return $this->proxyDumper;
430412
}
431413

432-
/**
433-
* @param ServiceReferenceGraphEdge[] $edges
434-
*/
435-
private function analyzeCircularReferences(string $sourceId, array $edges, array &$checkedNodes, array &$currentPath = [], bool $byConstructor = true)
414+
private function analyzeReferences()
436415
{
437-
$checkedNodes[$sourceId] = true;
438-
$currentPath[$sourceId] = $byConstructor;
416+
(new AnalyzeServiceReferencesPass(false, !$this->getProxyDumper() instanceof NullDumper))->process($this->container);
417+
$checkedNodes = [];
418+
$this->circularReferences = [];
419+
$this->singleUsePrivateIds = [];
420+
foreach ($this->container->getCompiler()->getServiceReferenceGraph()->getNodes() as $id => $node) {
421+
if (!$node->getValue() instanceof Definition) {
422+
continue;
423+
}
439424

440-
foreach ($edges as $edge) {
441-
$node = $edge->getDestNode();
442-
$id = $node->getId();
425+
if ($this->isSingleUsePrivateNode($node)) {
426+
$this->singleUsePrivateIds[$id] = $id;
427+
}
443428

444-
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());
429+
$newNodes = [];
430+
if (!$this->collectCircularReferences($id, $node->getOutEdges(), $checkedNodes, $newNodes)) {
431+
foreach ($newNodes as $newNodeId => $_) {
432+
$checkedNodes[$newNodeId] = [];
433+
}
434+
continue;
452435
}
453-
}
454-
unset($currentPath[$sourceId]);
455-
}
456436

457-
private function connectCircularReferences(string $sourceId, array &$currentPath, bool $byConstructor, array &$subPath = [])
458-
{
459-
$currentPath[$sourceId] = $subPath[$sourceId] = $byConstructor;
437+
$nodesToFlatten = $newNodes;
438+
do {
439+
$changedNodes = [];
440+
foreach ($nodesToFlatten as $newNodeId => $_) {
441+
$deps = &$checkedNodes[$newNodeId];
442+
foreach ($deps as $id => [$path, $depsByConstructor]) {
443+
foreach ($checkedNodes[$id] as $depsId => [$subPath, $subDepsByConstructor]) {
444+
if (!isset($deps[$depsId]) || ($depsByConstructor && $subDepsByConstructor && !$deps[$depsId][1])) {
445+
array_unshift($subPath, $id);
446+
$deps[$depsId] = [$subPath, $depsByConstructor && $subDepsByConstructor];
447+
$changedNodes += $newNodes[$newNodeId] ?? [];
448+
}
449+
}
450+
}
451+
}
452+
} while ($nodesToFlatten = $changedNodes);
460453

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);
454+
foreach ($newNodes as $newNodeId => $_) {
455+
if (null !== $n = $checkedNodes[$newNodeId][$newNodeId] ?? null) {
456+
$this->addCircularReferences($newNodeId, $n[0], $n[1]);
457+
}
466458
}
467459
}
468-
unset($currentPath[$sourceId], $subPath[$sourceId]);
460+
461+
$this->container->getCompiler()->getServiceReferenceGraph()->clear();
462+
$this->singleUsePrivateIds = array_diff_key($this->singleUsePrivateIds, $this->circularReferences);
469463
}
470464

471-
private function addCircularReferences(string $id, array $currentPath, bool $byConstructor)
465+
private function collectCircularReferences(string $sourceId, array $edges, array &$checkedNodes, array &$newNodes, array $path = []): bool
472466
{
473-
$currentPath[$id] = $byConstructor;
474-
$circularRefs = [];
467+
$path[$sourceId] = true;
468+
$checkedNodes[$sourceId] = [];
469+
$newNodes[$sourceId] = [];
470+
$circular = false;
471+
foreach ($edges as $edge) {
472+
$node = $edge->getDestNode();
473+
$id = $node->getId();
474+
if (!$node->getValue() instanceof Definition || $sourceId === $id || $edge->isLazy() || $edge->isWeak()) {
475+
continue;
476+
}
475477

476-
foreach (array_reverse($currentPath) as $parentId => $v) {
477-
$byConstructor = $byConstructor && $v;
478-
$circularRefs[] = $parentId;
478+
if (isset($path[$id])) {
479+
$circular = true;
480+
} elseif (!isset($checkedNodes[$id])) {
481+
$circular = $this->collectCircularReferences($id, $node->getOutEdges(), $checkedNodes, $newNodes, $path) || $circular;
482+
}
479483

480-
if ($parentId === $id) {
481-
break;
484+
$checkedNodes[$sourceId][$id] = [[], $edge->isReferencedByConstructor()];
485+
if (isset($newNodes[$id])) {
486+
$newNodes[$id][$sourceId] = true;
482487
}
483488
}
489+
unset($path[$sourceId]);
484490

485-
$currentId = $id;
486-
foreach ($circularRefs as $parentId) {
491+
return $circular;
492+
}
493+
494+
private function addCircularReferences(string $sourceId, array $currentPath, bool $byConstructor)
495+
{
496+
$currentId = $sourceId;
497+
$currentPath = array_reverse($currentPath);
498+
$currentPath[] = $currentId;
499+
foreach ($currentPath as $parentId) {
487500
if (empty($this->circularReferences[$parentId][$currentId])) {
488501
$this->circularReferences[$parentId][$currentId] = $byConstructor;
489502
}

0 commit comments

Comments
 (0)