Merge branch '3.4' into 4.1
* 3.4: [DI] fix combinatorial explosion when analyzing the service graph [Debug] workaround opcache bug mutating "$this" !?!
This commit is contained in:
commit
bfe2357ffa
2
phpunit
2
phpunit
@ -1,7 +1,7 @@
|
|||||||
#!/usr/bin/env php
|
#!/usr/bin/env php
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
// Cache-Id: https://github.com/symfony/phpunit-bridge/commit/66ffffcd8a6bb23aec847c8bdfb918610399499a
|
// Cache-Id: https://github.com/symfony/phpunit-bridge/commit/2155067dfc73e0e77dbc26f236af17e4df552de5
|
||||||
|
|
||||||
if (!file_exists(__DIR__.'/vendor/symfony/phpunit-bridge/bin/simple-phpunit')) {
|
if (!file_exists(__DIR__.'/vendor/symfony/phpunit-bridge/bin/simple-phpunit')) {
|
||||||
echo "Unable to find the `simple-phpunit` script in `vendor/symfony/phpunit-bridge/bin/`.\nPlease run `composer update` before running this command.\n";
|
echo "Unable to find the `simple-phpunit` script in `vendor/symfony/phpunit-bridge/bin/`.\nPlease run `composer update` before running this command.\n";
|
||||||
|
@ -137,14 +137,14 @@ class DebugClassLoader
|
|||||||
try {
|
try {
|
||||||
if ($this->isFinder && !isset($this->loaded[$class])) {
|
if ($this->isFinder && !isset($this->loaded[$class])) {
|
||||||
$this->loaded[$class] = true;
|
$this->loaded[$class] = true;
|
||||||
if ($file = $this->classLoader[0]->findFile($class) ?: false) {
|
if (!$file = $this->classLoader[0]->findFile($class) ?: false) {
|
||||||
$wasCached = \function_exists('opcache_is_script_cached') && @opcache_is_script_cached($file);
|
// no-op
|
||||||
|
} elseif (\function_exists('opcache_is_script_cached') && @opcache_is_script_cached($file)) {
|
||||||
require $file;
|
require $file;
|
||||||
|
|
||||||
if ($wasCached) {
|
return;
|
||||||
return;
|
} else {
|
||||||
}
|
require $file;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
\call_user_func($this->classLoader, $class);
|
\call_user_func($this->classLoader, $class);
|
||||||
|
@ -115,13 +115,19 @@ class InlineServiceDefinitionsPass extends AbstractRecursivePass implements Repe
|
|||||||
}
|
}
|
||||||
|
|
||||||
$ids = array();
|
$ids = array();
|
||||||
|
$isReferencedByConstructor = false;
|
||||||
foreach ($graph->getNode($id)->getInEdges() as $edge) {
|
foreach ($graph->getNode($id)->getInEdges() as $edge) {
|
||||||
|
$isReferencedByConstructor = $isReferencedByConstructor || $edge->isReferencedByConstructor();
|
||||||
if ($edge->isWeak()) {
|
if ($edge->isWeak()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
$ids[] = $edge->getSourceNode()->getId();
|
$ids[] = $edge->getSourceNode()->getId();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!$ids) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if (\count(array_unique($ids)) > 1) {
|
if (\count(array_unique($ids)) > 1) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -130,6 +136,10 @@ class InlineServiceDefinitionsPass extends AbstractRecursivePass implements Repe
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return !$ids || $this->container->getDefinition($ids[0])->isShared();
|
if ($isReferencedByConstructor && $this->container->getDefinition($ids[0])->isLazy() && ($definition->getProperties() || $definition->getMethodCalls() || $definition->getConfigurator())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->container->getDefinition($ids[0])->isShared();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -156,17 +156,18 @@ class PhpDumper extends Dumper
|
|||||||
}
|
}
|
||||||
|
|
||||||
(new AnalyzeServiceReferencesPass(false, !$this->getProxyDumper() instanceof NullDumper))->process($this->container);
|
(new AnalyzeServiceReferencesPass(false, !$this->getProxyDumper() instanceof NullDumper))->process($this->container);
|
||||||
|
$checkedNodes = array();
|
||||||
$this->circularReferences = array();
|
$this->circularReferences = array();
|
||||||
foreach (array(true, false) as $byConstructor) {
|
foreach ($this->container->getCompiler()->getServiceReferenceGraph()->getNodes() as $id => $node) {
|
||||||
foreach ($this->container->getCompiler()->getServiceReferenceGraph()->getNodes() as $id => $node) {
|
if (!$node->getValue() instanceof Definition) {
|
||||||
if (!$node->getValue() instanceof Definition) {
|
continue;
|
||||||
continue;
|
}
|
||||||
}
|
if (!isset($checkedNodes[$id])) {
|
||||||
$currentPath = array($id => true);
|
$this->analyzeCircularReferences($id, $node->getOutEdges(), $checkedNodes);
|
||||||
$this->analyzeCircularReferences($node->getOutEdges(), $currentPath, $id, $byConstructor);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$this->container->getCompiler()->getServiceReferenceGraph()->clear();
|
$this->container->getCompiler()->getServiceReferenceGraph()->clear();
|
||||||
|
$checkedNodes = array();
|
||||||
|
|
||||||
$this->docStar = $options['debug'] ? '*' : '';
|
$this->docStar = $options['debug'] ? '*' : '';
|
||||||
|
|
||||||
@ -307,12 +308,12 @@ EOF;
|
|||||||
return $this->proxyDumper;
|
return $this->proxyDumper;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function analyzeCircularReferences(array $edges, &$currentPath, $sourceId, $byConstructor)
|
private function analyzeCircularReferences($sourceId, array $edges, &$checkedNodes, &$currentPath = array())
|
||||||
{
|
{
|
||||||
|
$checkedNodes[$sourceId] = true;
|
||||||
|
$currentPath[$sourceId] = $sourceId;
|
||||||
|
|
||||||
foreach ($edges as $edge) {
|
foreach ($edges as $edge) {
|
||||||
if ($byConstructor && !$edge->isReferencedByConstructor()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
$node = $edge->getDestNode();
|
$node = $edge->getDestNode();
|
||||||
$id = $node->getId();
|
$id = $node->getId();
|
||||||
|
|
||||||
@ -321,20 +322,42 @@ EOF;
|
|||||||
} elseif (isset($currentPath[$id])) {
|
} elseif (isset($currentPath[$id])) {
|
||||||
$currentId = $id;
|
$currentId = $id;
|
||||||
foreach (array_reverse($currentPath) as $parentId) {
|
foreach (array_reverse($currentPath) as $parentId) {
|
||||||
if (!isset($this->circularReferences[$parentId][$currentId])) {
|
$this->circularReferences[$parentId][$currentId] = $currentId;
|
||||||
$this->circularReferences[$parentId][$currentId] = $byConstructor;
|
|
||||||
}
|
|
||||||
if ($parentId === $id) {
|
if ($parentId === $id) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
$currentId = $parentId;
|
$currentId = $parentId;
|
||||||
}
|
}
|
||||||
} else {
|
} elseif (!isset($checkedNodes[$id])) {
|
||||||
$currentPath[$id] = $id;
|
$this->analyzeCircularReferences($id, $node->getOutEdges(), $checkedNodes, $currentPath);
|
||||||
$this->analyzeCircularReferences($node->getOutEdges(), $currentPath, $id, $byConstructor);
|
} elseif (isset($this->circularReferences[$id])) {
|
||||||
unset($currentPath[$id]);
|
$this->connectCircularReferences($id, $currentPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
unset($currentPath[$sourceId]);
|
||||||
|
}
|
||||||
|
|
||||||
|
private function connectCircularReferences($sourceId, &$currentPath, &$subPath = array())
|
||||||
|
{
|
||||||
|
$subPath[$sourceId] = $sourceId;
|
||||||
|
$currentPath[$sourceId] = $sourceId;
|
||||||
|
|
||||||
|
foreach ($this->circularReferences[$sourceId] as $id) {
|
||||||
|
if (isset($currentPath[$id])) {
|
||||||
|
$currentId = $id;
|
||||||
|
foreach (array_reverse($currentPath) as $parentId) {
|
||||||
|
$this->circularReferences[$parentId][$currentId] = $currentId;
|
||||||
|
if ($parentId === $id) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
$currentId = $parentId;
|
||||||
|
}
|
||||||
|
} elseif (!isset($subPath[$id]) && isset($this->circularReferences[$id])) {
|
||||||
|
$this->connectCircularReferences($id, $currentPath, $subPath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unset($currentPath[$sourceId]);
|
||||||
|
unset($subPath[$sourceId]);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function collectLineage($class, array &$lineage)
|
private function collectLineage($class, array &$lineage)
|
||||||
@ -539,8 +562,11 @@ EOF;
|
|||||||
|
|
||||||
if (\is_array($callable)) {
|
if (\is_array($callable)) {
|
||||||
if ($callable[0] instanceof Reference
|
if ($callable[0] instanceof Reference
|
||||||
|| ($callable[0] instanceof Definition && $this->definitionVariables->contains($callable[0]))) {
|
|| ($callable[0] instanceof Definition && $this->definitionVariables->contains($callable[0]))
|
||||||
return sprintf(" %s->%s(\$%s);\n", $this->dumpValue($callable[0]), $callable[1], $variableName);
|
) {
|
||||||
|
$callable[0] = $this->dumpValue($callable[0]);
|
||||||
|
|
||||||
|
return sprintf(' '.('$' === $callable[0][0] ? '%s' : '(%s)')."->%s(\$%s);\n", $callable[0], $callable[1], $variableName);
|
||||||
}
|
}
|
||||||
|
|
||||||
$class = $this->dumpValue($callable[0]);
|
$class = $this->dumpValue($callable[0]);
|
||||||
@ -691,7 +717,7 @@ EOF;
|
|||||||
|
|
||||||
$hasSelfRef = isset($this->circularReferences[$id][$targetId]);
|
$hasSelfRef = isset($this->circularReferences[$id][$targetId]);
|
||||||
$forConstructor = $forConstructor && !isset($this->definitionVariables[$definition]);
|
$forConstructor = $forConstructor && !isset($this->definitionVariables[$definition]);
|
||||||
$code = $hasSelfRef && $this->circularReferences[$id][$targetId] && !$forConstructor ? $this->addInlineService($id, $definition, $definition) : '';
|
$code = $hasSelfRef && !$forConstructor ? $this->addInlineService($id, $definition, $definition) : '';
|
||||||
|
|
||||||
if (isset($this->referenceVariables[$targetId]) || (2 > $callCount && (!$hasSelfRef || !$forConstructor))) {
|
if (isset($this->referenceVariables[$targetId]) || (2 > $callCount && (!$hasSelfRef || !$forConstructor))) {
|
||||||
return $code;
|
return $code;
|
||||||
|
Reference in New Issue
Block a user