[DI] fine tune dumped factories

This commit is contained in:
Nicolas Grekas 2018-05-13 23:24:43 +02:00
parent 965e48482b
commit 88ecd0dc9a
5 changed files with 36 additions and 24 deletions

View File

@ -17,6 +17,7 @@ use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
use Symfony\Component\DependencyInjection\Variable;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Compiler\AnalyzeServiceReferencesPass;
use Symfony\Component\DependencyInjection\Compiler\ServiceReferenceGraphNode;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\DependencyInjection\ContainerInterface;
@ -68,6 +69,7 @@ class PhpDumper extends Dumper
private $inlineRequires;
private $inlinedRequires = array();
private $circularReferences = array();
private $singleUsePrivateIds = array();
/**
* @var ProxyDumper
@ -141,10 +143,14 @@ class PhpDumper extends Dumper
(new AnalyzeServiceReferencesPass())->process($this->container);
$this->circularReferences = array();
$this->singleUsePrivateIds = array();
$checkedNodes = array();
foreach ($this->container->getCompiler()->getServiceReferenceGraph()->getNodes() as $id => $node) {
$currentPath = array($id => $id);
$this->analyzeCircularReferences($node->getOutEdges(), $checkedNodes, $currentPath);
if ($this->isSingleUsePrivateNode($node)) {
$this->singleUsePrivateIds[$id] = $id;
}
}
$this->container->getCompiler()->getServiceReferenceGraph()->clear();
@ -526,7 +532,7 @@ EOTXT
$isProxyCandidate = $this->getProxyDumper()->isProxyCandidate($definition);
$instantiation = '';
if (!$isProxyCandidate && $definition->isShared()) {
if (!$isProxyCandidate && $definition->isShared() && !isset($this->singleUsePrivateIds[$id])) {
$instantiation = sprintf('$this->%s[\'%s\'] = %s', $this->container->getDefinition($id)->isPublic() ? 'services' : 'privates', $id, $isSimpleInstance ? '' : '$instance');
} elseif (!$isSimpleInstance) {
$instantiation = '$instance';
@ -819,7 +825,7 @@ EOF;
$definitions = $this->container->getDefinitions();
ksort($definitions);
foreach ($definitions as $id => $definition) {
if (!$definition->isSynthetic() && !$this->isHotPath($definition)) {
if (!$definition->isSynthetic() && !$this->isHotPath($definition) && ($definition->isPublic() || !$this->isTrivialInstance($definition))) {
$code = $this->addService($id, $definition, $file);
if (!$definition->isShared()) {
@ -1662,7 +1668,7 @@ EOF;
$code = 'null';
} elseif ($this->isTrivialInstance($definition)) {
$code = substr($this->addNewInstance($definition, '', '', $id), 8, -2);
if ($definition->isShared()) {
if ($definition->isShared() && !isset($this->singleUsePrivateIds[$id])) {
$code = sprintf('$this->%s[\'%s\'] = %s', $definition->isPublic() ? 'services' : 'privates', $id, $code);
}
} elseif ($this->asFiles && !$this->isHotPath($definition)) {
@ -1674,7 +1680,7 @@ EOF;
} else {
$code = sprintf('$this->%s()', $this->generateMethodName($id));
}
if ($definition->isShared()) {
if ($definition->isShared() && !isset($this->singleUsePrivateIds[$id])) {
$code = sprintf('($this->%s[\'%s\'] ?? %s)', $definition->isPublic() ? 'services' : 'privates', $id, $code);
}
@ -1798,6 +1804,22 @@ EOF;
return $this->hotPathTag && $definition->hasTag($this->hotPathTag) && !$definition->isDeprecated();
}
private function isSingleUsePrivateNode(ServiceReferenceGraphNode $node): bool
{
if ($node->getValue()->isPublic()) {
return false;
}
$ids = array();
foreach ($node->getInEdges() as $edge) {
if ($edge->isLazy() || !$edge->getSourceNode()->getValue()->isShared()) {
return false;
}
$ids[$edge->getSourceNode()->getId()] = true;
}
return 1 === \count($ids);
}
private function export($value)
{
if (null !== $this->targetDirRegex && is_string($value) && preg_match($this->targetDirRegex, $value, $matches, PREG_OFFSET_CAPTURE)) {

View File

@ -155,7 +155,7 @@ use Symfony\Component\DependencyInjection\Exception\RuntimeException;
// This file has been auto-generated by the Symfony Dependency Injection Component for internal use.
// Returns the public 'factory_service_simple' shared service.
return $this->services['factory_service_simple'] = ($this->privates['factory_simple'] ?? $this->load('getFactorySimpleService.php'))->getInstance();
return $this->services['factory_service_simple'] = $this->load('getFactorySimpleService.php')->getInstance();
[Container%s/getFactorySimpleService.php] => <?php
@ -167,7 +167,7 @@ use Symfony\Component\DependencyInjection\Exception\RuntimeException;
@trigger_error('The "factory_simple" service is deprecated. You should stop using it, as it will soon be removed.', E_USER_DEPRECATED);
return $this->privates['factory_simple'] = new \SimpleFactoryClass('foo');
return new \SimpleFactoryClass('foo');
[Container%s/getFooService.php] => <?php
@ -326,7 +326,7 @@ use Symfony\Component\DependencyInjection\Exception\RuntimeException;
// This file has been auto-generated by the Symfony Dependency Injection Component for internal use.
// Returns the public 'runtime_error' shared service.
return $this->services['runtime_error'] = new \stdClass(($this->privates['errored_definition'] ?? $this->load('getErroredDefinitionService.php')));
return $this->services['runtime_error'] = new \stdClass($this->load('getErroredDefinitionService.php'));
[Container%s/getServiceFromStaticMethodService.php] => <?php
@ -351,16 +351,6 @@ return $this->services['tagged_iterator'] = new \Bar(new RewindableGenerator(fun
yield 1 => ($this->privates['tagged_iterator_foo'] ?? $this->privates['tagged_iterator_foo'] = new \Bar());
}, 2));
[Container%s/getTaggedIteratorFooService.php] => <?php
use Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
// This file has been auto-generated by the Symfony Dependency Injection Component for internal use.
// Returns the private 'tagged_iterator_foo' shared service.
return $this->privates['tagged_iterator_foo'] = new \Bar();
[Container%s/ProjectServiceContainer.php] => <?php
namespace Container%s;

View File

@ -243,7 +243,7 @@ class ProjectServiceContainer extends Container
*/
protected function getFactoryServiceSimpleService()
{
return $this->services['factory_service_simple'] = ($this->privates['factory_simple'] ?? $this->getFactorySimpleService())->getInstance();
return $this->services['factory_service_simple'] = $this->getFactorySimpleService()->getInstance();
}
/**
@ -381,7 +381,7 @@ class ProjectServiceContainer extends Container
*/
protected function getRuntimeErrorService()
{
return $this->services['runtime_error'] = new \stdClass(($this->privates['errored_definition'] ?? $this->getErroredDefinitionService()));
return $this->services['runtime_error'] = new \stdClass($this->getErroredDefinitionService());
}
/**
@ -428,7 +428,7 @@ class ProjectServiceContainer extends Container
{
@trigger_error('The "factory_simple" service is deprecated. You should stop using it, as it will soon be removed.', E_USER_DEPRECATED);
return $this->privates['factory_simple'] = new \SimpleFactoryClass('foo');
return new \SimpleFactoryClass('foo');
}
public function getParameter($name)

View File

@ -243,7 +243,7 @@ class Symfony_DI_PhpDumper_Errored_Definition extends Container
*/
protected function getFactoryServiceSimpleService()
{
return $this->services['factory_service_simple'] = ($this->privates['factory_simple'] ?? $this->getFactorySimpleService())->getInstance();
return $this->services['factory_service_simple'] = $this->getFactorySimpleService()->getInstance();
}
/**
@ -381,7 +381,7 @@ class Symfony_DI_PhpDumper_Errored_Definition extends Container
*/
protected function getRuntimeErrorService()
{
return $this->services['runtime_error'] = new \stdClass(($this->privates['errored_definition'] ?? $this->getErroredDefinitionService()));
return $this->services['runtime_error'] = new \stdClass($this->getErroredDefinitionService());
}
/**
@ -428,7 +428,7 @@ class Symfony_DI_PhpDumper_Errored_Definition extends Container
{
@trigger_error('The "factory_simple" service is deprecated. You should stop using it, as it will soon be removed.', E_USER_DEPRECATED);
return $this->privates['factory_simple'] = new \SimpleFactoryClass('foo');
return new \SimpleFactoryClass('foo');
}
public function getParameter($name)

View File

@ -67,6 +67,6 @@ class ProjectServiceContainer extends Container
*/
protected function getPublicFooService()
{
return $this->services['public_foo'] = new \stdClass(($this->privates['private_foo'] ?? $this->privates['private_foo'] = new \stdClass()));
return $this->services['public_foo'] = new \stdClass(new \stdClass());
}
}