bug #28388 [DI] configure inlined services before injecting them when dumping the container (nicolas-grekas)

This PR was merged into the 3.4 branch.

Discussion
----------

[DI] configure inlined services before injecting them when dumping the container

| Q             | A
| ------------- | ---
| Branch?       | 3.4
| Bug fix?      | yes
| New feature?  | no
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | #28304
| License       | MIT
| Doc PR        | -

#28060 introduced a change in the way inline services are dumped: these instances could end up being configured *after* being injected. This breaks e.g. using Doctrine's Configuration instances, which are expected to be fully defined before being injected into their consumers.

Fixing this required a significant refactorization because I was just unable to reason with the heavily scrambled logic in place right now. The new logic is still non-trivial, but at least it's manageable, thus easier to get correct.

(Replaces #28385 which is the same applied to 4.1 - should help with merges.)

Commits
-------

e5c54053c4 [DI] configure inlined services before injecting them when dumping the container
This commit is contained in:
Nicolas Grekas 2018-09-08 14:58:42 +02:00
commit 5e237db55e
6 changed files with 187 additions and 315 deletions

View File

@ -55,7 +55,9 @@ class PhpDumper extends Dumper
private $definitionVariables;
private $referenceVariables;
private $variableCount;
private $reservedVariables = array('instance', 'class');
private $inlinedDefinitions;
private $serviceCalls;
private $reservedVariables = array('instance', 'class', 'this');
private $expressionLanguage;
private $targetDirRegex;
private $targetDirMaxMatches;
@ -295,63 +297,6 @@ EOF;
return $this->proxyDumper;
}
/**
* Generates Service local temp variables.
*
* @return string
*/
private function addServiceLocalTempVariables($cId, Definition $definition, \SplObjectStorage $inlinedDefinitions, array $serviceCalls, $preInstance = false)
{
$calls = array();
foreach ($inlinedDefinitions as $def) {
if ($preInstance && !$inlinedDefinitions[$def][1]) {
continue;
}
$this->getServiceCallsFromArguments(array($def->getArguments(), $def->getFactory()), $calls, $preInstance, $cId);
if ($def !== $definition) {
$arguments = array($def->getProperties(), $def->getMethodCalls(), $def->getConfigurator());
$this->getServiceCallsFromArguments($arguments, $calls, $preInstance && !$this->hasReference($cId, $arguments, true), $cId);
}
}
if (!isset($inlinedDefinitions[$definition])) {
$arguments = array($definition->getProperties(), $definition->getMethodCalls(), $definition->getConfigurator());
$this->getServiceCallsFromArguments($arguments, $calls, false, $cId);
}
$code = '';
foreach ($calls as $id => list($callCount)) {
if ('service_container' === $id || $id === $cId || isset($this->referenceVariables[$id])) {
continue;
}
if ($callCount <= 1 && $serviceCalls[$id][0] <= 1) {
continue;
}
$name = $this->getNextVariableName();
$this->referenceVariables[$id] = new Variable($name);
$reference = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE === $serviceCalls[$id][1] ? new Reference($id, $serviceCalls[$id][1]) : null;
$code .= sprintf(" \$%s = %s;\n", $name, $this->getServiceCall($id, $reference));
}
if ('' !== $code) {
if ($preInstance) {
$code .= <<<EOTXT
if (isset(\$this->services['$cId'])) {
return \$this->services['$cId'];
}
EOTXT;
}
$code .= "\n";
}
return $code;
}
private function analyzeCircularReferences(array $edges, &$checkedNodes, &$currentPath)
{
foreach ($edges as $edge) {
@ -436,19 +381,19 @@ EOTXT;
*
* @return string
*/
private function addServiceInclude($cId, Definition $definition, \SplObjectStorage $inlinedDefinitions, array $serviceCalls)
private function addServiceInclude($cId, Definition $definition)
{
$code = '';
if ($this->inlineRequires && !$this->isHotPath($definition)) {
$lineage = array();
foreach ($inlinedDefinitions as $def) {
foreach ($this->inlinedDefinitions as $def) {
if (!$def->isDeprecated() && \is_string($class = \is_array($factory = $def->getFactory()) && \is_string($factory[0]) ? $factory[0] : $def->getClass())) {
$this->collectLineage($class, $lineage);
}
}
foreach ($serviceCalls as $id => list($callCount, $behavior)) {
foreach ($this->serviceCalls as $id => list($callCount, $behavior)) {
if ('service_container' !== $id && $id !== $cId
&& ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE !== $behavior
&& $this->container->has($id)
@ -464,7 +409,7 @@ EOTXT;
}
}
foreach ($inlinedDefinitions as $def) {
foreach ($this->inlinedDefinitions as $def) {
if ($file = $def->getFile()) {
$code .= sprintf(" include_once %s;\n", $this->dumpValue($file));
}
@ -477,59 +422,6 @@ EOTXT;
return $code;
}
/**
* Generates the inline definition of a service.
*
* @return string
*
* @throws RuntimeException When the factory definition is incomplete
* @throws ServiceCircularReferenceException When a circular reference is detected
*/
private function addServiceInlinedDefinitions($id, Definition $definition, \SplObjectStorage $inlinedDefinitions, &$isSimpleInstance, $preInstance = false)
{
$code = '';
foreach ($inlinedDefinitions as $def) {
if ($definition === $def || isset($this->definitionVariables[$def])) {
continue;
}
if ($inlinedDefinitions[$def][0] <= 1 && !$def->getMethodCalls() && !$def->getProperties() && !$def->getConfigurator() && false === strpos($this->dumpValue($def->getClass()), '$')) {
continue;
}
if ($preInstance && !$inlinedDefinitions[$def][1]) {
continue;
}
$name = $this->getNextVariableName();
$this->definitionVariables[$def] = new Variable($name);
// a construct like:
// $a = new ServiceA(ServiceB $b); $b = new ServiceB(ServiceA $a);
// this is an indication for a wrong implementation, you can circumvent this problem
// by setting up your service structure like this:
// $b = new ServiceB();
// $a = new ServiceA(ServiceB $b);
// $b->setServiceA(ServiceA $a);
if (isset($inlinedDefinitions[$definition]) && $this->hasReference($id, array($def->getArguments(), $def->getFactory()))) {
throw new ServiceCircularReferenceException($id, array($id, '...', $id));
}
$code .= $this->addNewInstance($def, '$'.$name, ' = ', $id);
if (!$this->hasReference($id, array($def->getProperties(), $def->getMethodCalls(), $def->getConfigurator()), true, $inlinedDefinitions)) {
$code .= $this->addServiceProperties($def, $name);
$code .= $this->addServiceMethodCalls($def, $name);
$code .= $this->addServiceConfigurator($def, $name);
} else {
$isSimpleInstance = false;
}
$code .= "\n";
}
return $code;
}
/**
* Generates the service instance.
*
@ -566,14 +458,7 @@ EOTXT;
$instantiation .= ' = ';
}
$code = $this->addNewInstance($definition, $return, $instantiation, $id);
$this->referenceVariables[$id] = new Variable('instance');
if (!$isSimpleInstance) {
$code .= "\n";
}
return $code;
return $this->addNewInstance($definition, $return, $instantiation, $id);
}
/**
@ -658,40 +543,6 @@ EOTXT;
return $code;
}
/**
* Generates the inline definition setup.
*
* @return string
*
* @throws ServiceCircularReferenceException when the container contains a circular reference
*/
private function addServiceInlinedDefinitionsSetup($id, Definition $definition, \SplObjectStorage $inlinedDefinitions, $isSimpleInstance)
{
$code = '';
foreach ($inlinedDefinitions as $def) {
if ($definition === $def || !$this->hasReference($id, array($def->getProperties(), $def->getMethodCalls(), $def->getConfigurator()), true, $inlinedDefinitions)) {
continue;
}
// if the instance is simple, the return statement has already been generated
// so, the only possible way to get there is because of a circular reference
if ($isSimpleInstance) {
throw new ServiceCircularReferenceException($id, array($id, '...', $id));
}
$name = (string) $this->definitionVariables[$def];
$code .= $this->addServiceProperties($def, $name);
$code .= $this->addServiceMethodCalls($def, $name);
$code .= $this->addServiceConfigurator($def, $name);
}
if ('' !== $code && ($definition->getProperties() || $definition->getMethodCalls() || $definition->getConfigurator())) {
$code .= "\n";
}
return $code;
}
/**
* Adds configurator definition.
*
@ -742,6 +593,7 @@ EOTXT;
$this->definitionVariables = new \SplObjectStorage();
$this->referenceVariables = array();
$this->variableCount = 0;
$this->definitionVariables[$definition] = $this->referenceVariables[$id] = new Variable('instance');
$return = array();
@ -801,6 +653,11 @@ EOTXT;
EOF;
}
$this->serviceCalls = array();
$this->inlinedDefinitions = $this->getDefinitionsFromArguments(array($definition), null, $this->serviceCalls);
$code .= $this->addServiceInclude($id, $definition);
if ($this->getProxyDumper()->isProxyCandidate($definition)) {
$factoryCode = $asFile ? "\$this->load('%s.php', false)" : '$this->%s(false)';
$code .= $this->getProxyDumper()->getProxyFactoryCode($definition, $id, sprintf($factoryCode, $methodName));
@ -810,40 +667,22 @@ EOF;
$code .= sprintf(" @trigger_error(%s, E_USER_DEPRECATED);\n\n", $this->export($definition->getDeprecationMessage($id)));
}
$inlinedDefinitions = $this->getDefinitionsFromArguments(array($definition));
$constructorDefinitions = $this->getDefinitionsFromArguments(array($definition->getArguments(), $definition->getFactory()));
unset($constructorDefinitions[$definition]); // ensures $definition will be last
$otherDefinitions = new \SplObjectStorage();
$serviceCalls = array();
$head = $tail = '';
$arguments = array($definition->getArguments(), $definition->getFactory());
$this->addInlineVariables($head, $tail, $id, $arguments, true);
$code .= '' !== $head ? $head."\n" : '';
foreach ($inlinedDefinitions as $def) {
if ($def === $definition || isset($constructorDefinitions[$def])) {
$constructorDefinitions[$def] = $inlinedDefinitions[$def];
} else {
$otherDefinitions[$def] = $inlinedDefinitions[$def];
}
$arguments = array($def->getArguments(), $def->getFactory(), $def->getProperties(), $def->getMethodCalls(), $def->getConfigurator());
$this->getServiceCallsFromArguments($arguments, $serviceCalls, false, $id);
if ($arguments = array_filter(array($definition->getProperties(), $definition->getMethodCalls(), $definition->getConfigurator()))) {
$this->addInlineVariables($tail, $tail, $id, $arguments, false);
$tail .= '' !== $tail ? "\n" : '';
$tail .= $this->addServiceProperties($definition);
$tail .= $this->addServiceMethodCalls($definition);
$tail .= $this->addServiceConfigurator($definition);
}
$isSimpleInstance = !$definition->getProperties() && !$definition->getMethodCalls() && !$definition->getConfigurator();
$preInstance = isset($this->circularReferences[$id]) && !$this->getProxyDumper()->isProxyCandidate($definition) && $definition->isShared();
$code .=
$this->addServiceInclude($id, $definition, $inlinedDefinitions, $serviceCalls).
$this->addServiceLocalTempVariables($id, $definition, $constructorDefinitions, $serviceCalls, $preInstance).
$this->addServiceInlinedDefinitions($id, $definition, $constructorDefinitions, $isSimpleInstance, $preInstance).
$this->addServiceInstance($id, $definition, $isSimpleInstance).
$this->addServiceLocalTempVariables($id, $definition, $constructorDefinitions->offsetUnset($definition) ?: $constructorDefinitions, $serviceCalls).
$this->addServiceLocalTempVariables($id, $definition, $otherDefinitions, $serviceCalls).
$this->addServiceInlinedDefinitions($id, $definition, $constructorDefinitions, $isSimpleInstance).
$this->addServiceInlinedDefinitions($id, $definition, $otherDefinitions, $isSimpleInstance).
$this->addServiceInlinedDefinitionsSetup($id, $definition, $inlinedDefinitions, $isSimpleInstance).
$this->addServiceProperties($definition).
$this->addServiceMethodCalls($definition).
$this->addServiceConfigurator($definition).
(!$isSimpleInstance ? "\n return \$instance;\n" : '')
;
$code .= $this->addServiceInstance($id, $definition, '' === $tail)
.('' !== $tail ? "\n".$tail."\n return \$instance;\n" : '');
if ($asFile) {
$code = implode("\n", array_map(function ($line) { return $line ? substr($line, 8) : $line; }, explode("\n", $code)));
@ -851,12 +690,108 @@ EOF;
$code .= " }\n";
}
$this->definitionVariables = null;
$this->referenceVariables = null;
$this->definitionVariables = $this->inlinedDefinitions = null;
$this->referenceVariables = $this->serviceCalls = null;
return $code;
}
private function addInlineVariables(&$head, &$tail, $id, array $arguments, $forConstructor)
{
$hasSelfRef = false;
foreach ($arguments as $argument) {
if (\is_array($argument)) {
$hasSelfRef = $this->addInlineVariables($head, $tail, $id, $argument, $forConstructor) || $hasSelfRef;
} elseif ($argument instanceof Reference) {
$hasSelfRef = $this->addInlineReference($head, $tail, $id, $this->container->normalizeId($argument), $forConstructor) || $hasSelfRef;
} elseif ($argument instanceof Definition) {
$hasSelfRef = $this->addInlineService($head, $tail, $id, $argument, $forConstructor) || $hasSelfRef;
}
}
return $hasSelfRef;
}
private function addInlineReference(&$head, &$tail, $id, $targetId, $forConstructor)
{
if ('service_container' === $targetId || isset($this->referenceVariables[$targetId])) {
return isset($this->circularReferences[$id][$targetId]);
}
list($callCount, $behavior) = $this->serviceCalls[$targetId];
if (2 > $callCount && (!$forConstructor || !isset($this->circularReferences[$id][$targetId]))) {
return isset($this->circularReferences[$id][$targetId]);
}
$name = $this->getNextVariableName();
$this->referenceVariables[$targetId] = new Variable($name);
$reference = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE >= $behavior ? new Reference($targetId, $behavior) : null;
$code = sprintf(" \$%s = %s;\n", $name, $this->getServiceCall($targetId, $reference));
if (!isset($this->circularReferences[$id][$targetId])) {
$head .= $code;
return false;
}
if (!$forConstructor) {
$tail .= $code;
return true;
}
$head .= $code.sprintf(<<<'EOTXT'
if (isset($this->%s['%s'])) {
return $this->%1$s['%2$s'];
}
EOTXT
,
$this->container->getDefinition($id)->isPublic() ? 'services' : 'privates',
$id
);
return false;
}
private function addInlineService(&$head, &$tail, $id, Definition $definition, $forConstructor)
{
if (isset($this->definitionVariables[$definition])) {
return false;
}
$arguments = array($definition->getArguments(), $definition->getFactory());
if (2 > $this->inlinedDefinitions[$definition] && !$definition->getMethodCalls() && !$definition->getProperties() && !$definition->getConfigurator() && false === strpos($this->dumpValue($definition->getClass()), '$')) {
return $this->addInlineVariables($head, $tail, $id, $arguments, $forConstructor);
}
$name = $this->getNextVariableName();
$this->definitionVariables[$definition] = new Variable($name);
$code = '';
$hasSelfRef = $this->addInlineVariables($code, $tail, $id, $arguments, $forConstructor);
$code .= $this->addNewInstance($definition, '$'.$name, ' = ', $id);
$hasSelfRef ? $tail .= ('' !== $tail ? "\n" : '').$code : $head .= ('' !== $head ? "\n" : '').$code;
$code = '';
$arguments = array($definition->getProperties(), $definition->getMethodCalls(), $definition->getConfigurator());
$hasSelfRef = $this->addInlineVariables($code, $tail, $id, $arguments, false) || $hasSelfRef;
$code .= $this->addServiceProperties($definition, $name);
$code .= $this->addServiceMethodCalls($definition, $name);
$code .= $this->addServiceConfigurator($definition, $name);
if ('' !== $code) {
$hasSelfRef ? $tail .= ('' !== $tail ? "\n" : '').$code : $head .= $code;
}
return $hasSelfRef;
}
/**
* Adds multiple services.
*
@ -1574,31 +1509,7 @@ EOF;
return implode(' && ', $conditions);
}
/**
* Builds service calls from arguments.
*
* Populates $calls with "referenced id" => ["reference count", "invalid behavior"] pairs.
*/
private function getServiceCallsFromArguments(array $arguments, array &$calls, $preInstance, $callerId)
{
foreach ($arguments as $argument) {
if (\is_array($argument)) {
$this->getServiceCallsFromArguments($argument, $calls, $preInstance, $callerId);
} elseif ($argument instanceof Reference) {
$id = $this->container->normalizeId($argument);
if (!isset($calls[$id])) {
$calls[$id] = array((int) ($preInstance && isset($this->circularReferences[$callerId][$id])), $argument->getInvalidBehavior());
} else {
$calls[$id][1] = min($calls[$id][1], $argument->getInvalidBehavior());
}
++$calls[$id][0];
}
}
}
private function getDefinitionsFromArguments(array $arguments, $isConstructorArgument = true, \SplObjectStorage $definitions = null)
private function getDefinitionsFromArguments(array $arguments, \SplObjectStorage $definitions = null, array &$calls = array())
{
if (null === $definitions) {
$definitions = new \SplObjectStorage();
@ -1606,88 +1517,31 @@ EOF;
foreach ($arguments as $argument) {
if (\is_array($argument)) {
$this->getDefinitionsFromArguments($argument, $isConstructorArgument, $definitions);
$this->getDefinitionsFromArguments($argument, $definitions, $calls);
} elseif ($argument instanceof Reference) {
$id = $this->container->normalizeId($argument);
if (!isset($calls[$id])) {
$calls[$id] = array(0, $argument->getInvalidBehavior());
} else {
$calls[$id][1] = min($calls[$id][1], $argument->getInvalidBehavior());
}
++$calls[$id][0];
} elseif (!$argument instanceof Definition) {
// no-op
} elseif (isset($definitions[$argument])) {
$def = $definitions[$argument];
$definitions[$argument] = array(1 + $def[0], $isConstructorArgument || $def[1]);
$definitions[$argument] = 1 + $definitions[$argument];
} else {
$definitions[$argument] = array(1, $isConstructorArgument);
$this->getDefinitionsFromArguments($argument->getArguments(), $isConstructorArgument, $definitions);
$this->getDefinitionsFromArguments(array($argument->getFactory()), $isConstructorArgument, $definitions);
$this->getDefinitionsFromArguments($argument->getProperties(), false, $definitions);
$this->getDefinitionsFromArguments($argument->getMethodCalls(), false, $definitions);
$this->getDefinitionsFromArguments(array($argument->getConfigurator()), false, $definitions);
// move current definition last in the list
$def = $definitions[$argument];
unset($definitions[$argument]);
$definitions[$argument] = $def;
$definitions[$argument] = 1;
$arguments = array($argument->getArguments(), $argument->getFactory(), $argument->getProperties(), $argument->getMethodCalls(), $argument->getConfigurator());
$this->getDefinitionsFromArguments($arguments, $definitions, $calls);
}
}
return $definitions;
}
/**
* Checks if a service id has a reference.
*
* @param string $id
* @param array $arguments
* @param bool $deep
* @param array $visited
*
* @return bool
*/
private function hasReference($id, array $arguments, $deep = false, \SplObjectStorage $inlinedDefinitions = null, array &$visited = array())
{
if (!isset($this->circularReferences[$id])) {
return false;
}
foreach ($arguments as $argument) {
if (\is_array($argument)) {
if ($this->hasReference($id, $argument, $deep, $inlinedDefinitions, $visited)) {
return true;
}
continue;
} elseif ($argument instanceof Reference) {
$argumentId = $this->container->normalizeId($argument);
if ($id === $argumentId) {
return true;
}
if (!$deep || isset($visited[$argumentId]) || !isset($this->circularReferences[$argumentId])) {
continue;
}
$visited[$argumentId] = true;
$service = $this->container->getDefinition($argumentId);
} elseif ($argument instanceof Definition) {
if (isset($inlinedDefinitions[$argument])) {
return true;
}
$service = $argument;
} else {
continue;
}
// if the proxy manager is enabled, disable searching for references in lazy services,
// as these services will be instantiated lazily and don't have direct related references.
if ($service->isLazy() && !$this->getProxyDumper() instanceof NullDumper) {
continue;
}
if ($this->hasReference($id, array($service->getArguments(), $service->getFactory(), $service->getProperties(), $service->getMethodCalls(), $service->getConfigurator()), $deep, $inlinedDefinitions, $visited)) {
return true;
}
}
return false;
}
/**
* Dumps values.
*
@ -1711,7 +1565,7 @@ EOF;
return sprintf('array(%s)', implode(', ', $code));
} elseif ($value instanceof ArgumentInterface) {
$scope = array($this->definitionVariables, $this->referenceVariables, $this->variableCount);
$scope = array($this->definitionVariables, $this->referenceVariables);
$this->definitionVariables = $this->referenceVariables = null;
try {
@ -1758,7 +1612,7 @@ EOF;
return implode("\n", $code);
}
} finally {
list($this->definitionVariables, $this->referenceVariables, $this->variableCount) = $scope;
list($this->definitionVariables, $this->referenceVariables) = $scope;
}
} elseif ($value instanceof Definition) {
if (null !== $this->definitionVariables && $this->definitionVariables->contains($value)) {

View File

@ -850,7 +850,14 @@ class PhpDumperTest extends TestCase
$dumper = new PhpDumper($container);
$dumper->dump();
$this->assertStringEqualsFile(self::$fixturesPath.'/php/services_deep_graph.php', $dumper->dump());
$this->assertStringEqualsFile(self::$fixturesPath.'/php/services_deep_graph.php', $dumper->dump(array('class' => 'Symfony_DI_PhpDumper_Test_Deep_Graph')));
require self::$fixturesPath.'/php/services_deep_graph.php';
$container = new \Symfony_DI_PhpDumper_Test_Deep_Graph();
$this->assertInstanceOf(FooForDeepGraph::class, $container->get('foo'));
$this->assertEquals((object) array('p2' => (object) array('p3' => (object) array())), $container->get('foo')->bClone);
}
public function testHotPathOptimizations()
@ -1077,3 +1084,14 @@ class Rot13EnvVarProcessor implements EnvVarProcessorInterface
return array('rot13' => 'string');
}
}
class FooForDeepGraph
{
public $bClone;
public function __construct(\stdClass $a, \stdClass $b)
{
// clone to verify that $b has been fully initialized before
$this->bClone = clone $b;
}
}

View File

@ -121,6 +121,7 @@ class Symfony_DI_PhpDumper_Test_Almost_Circular_Private extends Container
$this->services['connection'] = $instance = new \stdClass($a, $b);
$a->subscriber = ${($_ = isset($this->services['subscriber']) ? $this->services['subscriber'] : $this->getSubscriberService()) && false ?: '_'};
$b->logger = ${($_ = isset($this->services['logger']) ? $this->services['logger'] : $this->getLoggerService()) && false ?: '_'};
return $instance;
@ -135,17 +136,19 @@ class Symfony_DI_PhpDumper_Test_Almost_Circular_Private extends Container
{
$a = new \stdClass();
$b = new \stdClass();
$c = new \stdClass();
$this->services['connection2'] = $instance = new \stdClass($a, $b);
$this->services['connection2'] = $instance = new \stdClass($a, $c);
$c = ${($_ = isset($this->services['manager2']) ? $this->services['manager2'] : $this->getManager2Service()) && false ?: '_'};
$b = ${($_ = isset($this->services['manager2']) ? $this->services['manager2'] : $this->getManager2Service()) && false ?: '_'};
$a->subscriber2 = new \stdClass($b);
$d = new \stdClass($instance);
$a->subscriber2 = new \stdClass($c);
$d->handler2 = new \stdClass($c);
$b->logger2 = $d;
$d->handler2 = new \stdClass($b);
$c->logger2 = $d;
return $instance;
}

View File

@ -169,6 +169,7 @@ class Symfony_DI_PhpDumper_Test_Almost_Circular_Public extends Container
$c = new \stdClass($instance);
$c->handler2 = new \stdClass(${($_ = isset($this->services['manager2']) ? $this->services['manager2'] : $this->getManager2Service()) && false ?: '_'});
$b->logger2 = $c;
return $instance;

View File

@ -14,7 +14,7 @@ use Symfony\Component\DependencyInjection\ParameterBag\FrozenParameterBag;
*
* @final since Symfony 3.3
*/
class ProjectServiceContainer extends Container
class Symfony_DI_PhpDumper_Test_Deep_Graph extends Container
{
private $parameters;
private $targetDirs = array();
@ -58,13 +58,13 @@ class ProjectServiceContainer extends Container
/**
* Gets the public 'bar' shared service.
*
* @return \c5
* @return \stdClass
*/
protected function getBarService()
{
$this->services['bar'] = $instance = new \c5();
$this->services['bar'] = $instance = new \stdClass();
$instance->p5 = new \c6(${($_ = isset($this->services['foo']) ? $this->services['foo'] : $this->getFooService()) && false ?: '_'});
$instance->p5 = new \stdClass(${($_ = isset($this->services['foo']) ? $this->services['foo'] : $this->getFooService()) && false ?: '_'});
return $instance;
}
@ -72,7 +72,7 @@ class ProjectServiceContainer extends Container
/**
* Gets the public 'foo' shared service.
*
* @return \c1
* @return \Symfony\Component\DependencyInjection\Tests\Dumper\FooForDeepGraph
*/
protected function getFooService()
{
@ -82,15 +82,11 @@ class ProjectServiceContainer extends Container
return $this->services['foo'];
}
$b = new \c2();
$this->services['foo'] = $instance = new \c1($a, $b);
$c = new \c3();
$c->p3 = new \c4();
$b = new \stdClass();
$c = new \stdClass();
$c->p3 = new \stdClass();
$b->p2 = $c;
return $instance;
return $this->services['foo'] = new \Symfony\Component\DependencyInjection\Tests\Dumper\FooForDeepGraph($a, $b);
}
}

View File

@ -1,24 +1,24 @@
services:
foo:
class: c1
class: Symfony\Component\DependencyInjection\Tests\Dumper\FooForDeepGraph
public: true
arguments:
- '@bar'
- !service
class: c2
class: stdClass
properties:
p2: !service
class: c3
class: stdClass
properties:
p3: !service
class: c4
class: stdClass
bar:
class: c5
class: stdClass
public: true
properties:
p5: !service
class: c6
class: stdClass
arguments: ['@foo']