Skip to content

Commit c2061bc

Browse files
Merge branch '4.1' into 4.2
* 4.1: [DI] fix combinatorial explosion when analyzing the service graph [Debug] workaround opcache bug mutating "$this" !?!
2 parents 32bd3be + 1f77f2a commit c2061bc

File tree

2 files changed

+55
-23
lines changed

2 files changed

+55
-23
lines changed

Compiler/InlineServiceDefinitionsPass.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,9 @@ private function isInlineableDefinition($id, Definition $definition)
191191

192192
$srcIds = array();
193193
$srcCount = 0;
194+
$isReferencedByConstructor = false;
194195
foreach ($this->graph->getNode($id)->getInEdges() as $edge) {
196+
$isReferencedByConstructor = $isReferencedByConstructor || $edge->isReferencedByConstructor();
195197
$srcId = $edge->getSourceNode()->getId();
196198
$this->connectedIds[$srcId] = true;
197199
if ($edge->isWeak()) {
@@ -211,6 +213,10 @@ private function isInlineableDefinition($id, Definition $definition)
211213
return false;
212214
}
213215

216+
if ($isReferencedByConstructor && $this->container->getDefinition($srcId)->isLazy() && ($definition->getProperties() || $definition->getMethodCalls() || $definition->getConfigurator())) {
217+
return false;
218+
}
219+
214220
return $this->container->getDefinition($srcId)->isShared();
215221
}
216222
}

Dumper/PhpDumper.php

Lines changed: 49 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -171,21 +171,22 @@ public function dump(array $options = array())
171171
}
172172

173173
(new AnalyzeServiceReferencesPass(false, !$this->getProxyDumper() instanceof NullDumper))->process($this->container);
174+
$checkedNodes = array();
174175
$this->circularReferences = array();
175176
$this->singleUsePrivateIds = array();
176-
foreach (array(true, false) as $byConstructor) {
177-
foreach ($this->container->getCompiler()->getServiceReferenceGraph()->getNodes() as $id => $node) {
178-
if (!$node->getValue() instanceof Definition) {
179-
continue;
180-
}
181-
$currentPath = array($id => $id);
182-
$this->analyzeCircularReferences($node->getOutEdges(), $currentPath, $id, $byConstructor);
183-
if ($this->isSingleUsePrivateNode($node)) {
184-
$this->singleUsePrivateIds[$id] = $id;
185-
}
177+
foreach ($this->container->getCompiler()->getServiceReferenceGraph()->getNodes() as $id => $node) {
178+
if (!$node->getValue() instanceof Definition) {
179+
continue;
180+
}
181+
if (!isset($checkedNodes[$id])) {
182+
$this->analyzeCircularReferences($id, $node->getOutEdges(), $checkedNodes);
183+
}
184+
if ($this->isSingleUsePrivateNode($node)) {
185+
$this->singleUsePrivateIds[$id] = $id;
186186
}
187187
}
188188
$this->container->getCompiler()->getServiceReferenceGraph()->clear();
189+
$checkedNodes = array();
189190

190191
$this->docStar = $options['debug'] ? '*' : '';
191192

@@ -337,12 +338,12 @@ private function getProxyDumper(): ProxyDumper
337338
return $this->proxyDumper;
338339
}
339340

340-
private function analyzeCircularReferences(array $edges, &$currentPath, $sourceId, $byConstructor)
341+
private function analyzeCircularReferences($sourceId, array $edges, &$checkedNodes, &$currentPath = array())
341342
{
343+
$checkedNodes[$sourceId] = true;
344+
$currentPath[$sourceId] = $sourceId;
345+
342346
foreach ($edges as $edge) {
343-
if ($byConstructor && !$edge->isReferencedByConstructor()) {
344-
continue;
345-
}
346347
$node = $edge->getDestNode();
347348
$id = $node->getId();
348349

@@ -351,20 +352,42 @@ private function analyzeCircularReferences(array $edges, &$currentPath, $sourceI
351352
} elseif (isset($currentPath[$id])) {
352353
$currentId = $id;
353354
foreach (array_reverse($currentPath) as $parentId) {
354-
if (!isset($this->circularReferences[$parentId][$currentId])) {
355-
$this->circularReferences[$parentId][$currentId] = $byConstructor;
355+
$this->circularReferences[$parentId][$currentId] = $currentId;
356+
if ($parentId === $id) {
357+
break;
356358
}
359+
$currentId = $parentId;
360+
}
361+
} elseif (!isset($checkedNodes[$id])) {
362+
$this->analyzeCircularReferences($id, $node->getOutEdges(), $checkedNodes, $currentPath);
363+
} elseif (isset($this->circularReferences[$id])) {
364+
$this->connectCircularReferences($id, $currentPath);
365+
}
366+
}
367+
unset($currentPath[$sourceId]);
368+
}
369+
370+
private function connectCircularReferences($sourceId, &$currentPath, &$subPath = array())
371+
{
372+
$subPath[$sourceId] = $sourceId;
373+
$currentPath[$sourceId] = $sourceId;
374+
375+
foreach ($this->circularReferences[$sourceId] as $id) {
376+
if (isset($currentPath[$id])) {
377+
$currentId = $id;
378+
foreach (array_reverse($currentPath) as $parentId) {
379+
$this->circularReferences[$parentId][$currentId] = $currentId;
357380
if ($parentId === $id) {
358381
break;
359382
}
360383
$currentId = $parentId;
361384
}
362-
} else {
363-
$currentPath[$id] = $id;
364-
$this->analyzeCircularReferences($node->getOutEdges(), $currentPath, $id, $byConstructor);
365-
unset($currentPath[$id]);
385+
} elseif (!isset($subPath[$id]) && isset($this->circularReferences[$id])) {
386+
$this->connectCircularReferences($id, $currentPath, $subPath);
366387
}
367388
}
389+
unset($currentPath[$sourceId]);
390+
unset($subPath[$sourceId]);
368391
}
369392

370393
private function collectLineage($class, array &$lineage)
@@ -572,8 +595,11 @@ private function addServiceConfigurator(Definition $definition, string $variable
572595

573596
if (\is_array($callable)) {
574597
if ($callable[0] instanceof Reference
575-
|| ($callable[0] instanceof Definition && $this->definitionVariables->contains($callable[0]))) {
576-
return sprintf(" %s->%s(\$%s);\n", $this->dumpValue($callable[0]), $callable[1], $variableName);
598+
|| ($callable[0] instanceof Definition && $this->definitionVariables->contains($callable[0]))
599+
) {
600+
$callable[0] = $this->dumpValue($callable[0]);
601+
602+
return sprintf(' '.('$' === $callable[0][0] ? '%s' : '(%s)')."->%s(\$%s);\n", $callable[0], $callable[1], $variableName);
577603
}
578604

579605
$class = $this->dumpValue($callable[0]);
@@ -719,7 +745,7 @@ private function addInlineReference(string $id, Definition $definition, string $
719745

720746
$hasSelfRef = isset($this->circularReferences[$id][$targetId]);
721747
$forConstructor = $forConstructor && !isset($this->definitionVariables[$definition]);
722-
$code = $hasSelfRef && $this->circularReferences[$id][$targetId] && !$forConstructor ? $this->addInlineService($id, $definition, $definition) : '';
748+
$code = $hasSelfRef && !$forConstructor ? $this->addInlineService($id, $definition, $definition) : '';
723749

724750
if (isset($this->referenceVariables[$targetId]) || (2 > $callCount && (!$hasSelfRef || !$forConstructor))) {
725751
return $code;

0 commit comments

Comments
 (0)