From ed3c91910627ce7ad8a545712d4b694a81bcb4eb Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 27 Nov 2017 21:00:44 +0100 Subject: [PATCH] [DI] Fix circular reference when using setters --- .../DependencyInjection/Compiler/Compiler.php | 2 + .../Compiler/ServiceReferenceGraph.php | 3 + .../Compiler/ServiceReferenceGraphNode.php | 8 + .../DependencyInjection/Dumper/PhpDumper.php | 199 ++++++------------ .../Tests/ContainerBuilderTest.php | 20 +- .../Tests/Dumper/PhpDumperTest.php | 54 ++--- .../containers/container_almost_circular.php | 20 ++ .../Tests/Fixtures/php/services9_as_files.txt | 8 +- .../Tests/Fixtures/php/services9_compiled.php | 8 +- ...p => services_almost_circular_private.php} | 50 +++++ ...hp => services_almost_circular_public.php} | 53 +++++ ...uires.php => services_inline_requires.php} | 0 12 files changed, 236 insertions(+), 189 deletions(-) rename src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/{container_almost_circular_private.php => services_almost_circular_private.php} (60%) rename src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/{container_almost_circular_public.php => services_almost_circular_public.php} (68%) rename src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/{container_inline_requires.php => services_inline_requires.php} (100%) diff --git a/src/Symfony/Component/DependencyInjection/Compiler/Compiler.php b/src/Symfony/Component/DependencyInjection/Compiler/Compiler.php index a8499a02bc5f1..e39c9598549d8 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/Compiler.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/Compiler.php @@ -159,6 +159,8 @@ public function compile(ContainerBuilder $container) } throw $e; + } finally { + $this->getServiceReferenceGraph()->clear(); } } } diff --git a/src/Symfony/Component/DependencyInjection/Compiler/ServiceReferenceGraph.php b/src/Symfony/Component/DependencyInjection/Compiler/ServiceReferenceGraph.php index fb04c9a0b6e87..d040e66c4dac7 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/ServiceReferenceGraph.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/ServiceReferenceGraph.php @@ -75,6 +75,9 @@ public function getNodes() */ public function clear() { + foreach ($this->nodes as $node) { + $node->clear(); + } $this->nodes = array(); } diff --git a/src/Symfony/Component/DependencyInjection/Compiler/ServiceReferenceGraphNode.php b/src/Symfony/Component/DependencyInjection/Compiler/ServiceReferenceGraphNode.php index 3219d06e96989..1052d2c6ae59e 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/ServiceReferenceGraphNode.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/ServiceReferenceGraphNode.php @@ -107,4 +107,12 @@ public function getValue() { return $this->value; } + + /** + * Clears all edges. + */ + public function clear() + { + $this->inEdges = $this->outEdges = array(); + } } diff --git a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php index ca9f26309407c..83d82a508acc2 100644 --- a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php +++ b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php @@ -51,7 +51,6 @@ class PhpDumper extends Dumper */ const NON_FIRST_CHARS = 'abcdefghijklmnopqrstuvwxyz0123456789_'; - private $inlinedDefinitions; private $definitionVariables; private $referenceVariables; private $variableCount; @@ -84,8 +83,6 @@ public function __construct(ContainerBuilder $container) } parent::__construct($container); - - $this->inlinedDefinitions = new \SplObjectStorage(); } /** @@ -142,6 +139,7 @@ public function dump(array $options = array()) $currentPath = array($id => $id); $this->analyzeCircularReferences($node->getOutEdges(), $checkedNodes, $currentPath); } + $this->container->getCompiler()->getServiceReferenceGraph()->clear(); $this->docStar = $options['debug'] ? '*' : ''; @@ -270,31 +268,22 @@ private function getProxyDumper() /** * Generates Service local temp variables. * - * @param string $cId - * @param Definition $definition - * @param array $inlinedDefinitions - * * @return string */ - private function addServiceLocalTempVariables($cId, Definition $definition, array $inlinedDefinitions) + private function addServiceLocalTempVariables($cId, Definition $definition, \SplObjectStorage $inlinedDefinitions) { static $template = " \$%s = %s;\n"; - array_unshift($inlinedDefinitions, $definition); - $collectLineage = $this->inlineRequires && !$this->isHotPath($definition); - $isNonLazyShared = isset($this->circularReferences[$cId]) && !$this->getProxyDumper()->isProxyCandidate($definition) && $definition->isShared(); + $isNonLazyShared = isset($inlinedDefinitions[$definition]) && isset($this->circularReferences[$cId]) && !$this->getProxyDumper()->isProxyCandidate($definition) && $definition->isShared(); $lineage = $calls = $behavior = array(); foreach ($inlinedDefinitions as $iDefinition) { if ($collectLineage && !$iDefinition->isDeprecated() && $class = is_array($factory = $iDefinition->getFactory()) && is_string($factory[0]) ? $factory[0] : $iDefinition->getClass()) { $this->collectLineage($class, $lineage); } - $this->getServiceCallsFromArguments($iDefinition->getArguments(), $calls, $behavior, $isNonLazyShared, $cId); - $isPreInstantiation = $isNonLazyShared && $iDefinition !== $definition && !$this->hasReference($cId, $iDefinition->getMethodCalls(), true) && !$this->hasReference($cId, $iDefinition->getProperties(), true); - $this->getServiceCallsFromArguments($iDefinition->getMethodCalls(), $calls, $behavior, $isPreInstantiation, $cId); - $this->getServiceCallsFromArguments($iDefinition->getProperties(), $calls, $behavior, $isPreInstantiation, $cId); - $this->getServiceCallsFromArguments(array($iDefinition->getConfigurator()), $calls, $behavior, $isPreInstantiation, $cId); - $this->getServiceCallsFromArguments(array($iDefinition->getFactory()), $calls, $behavior, $isNonLazyShared, $cId); + $this->getServiceCallsFromArguments(array($iDefinition->getArguments(), $iDefinition->getFactory()), $calls, $behavior, $isNonLazyShared, $cId); + $postArguments = array($iDefinition->getProperties(), $iDefinition->getMethodCalls(), $iDefinition->getConfigurator()); + $this->getServiceCallsFromArguments($postArguments, $calls, $behavior, $isNonLazyShared && $iDefinition !== $definition && !$this->hasReference($cId, $postArguments, true), $cId); } $code = ''; @@ -353,11 +342,6 @@ private function analyzeCircularReferences(array $edges, &$checkedNodes, &$curre $node = $edge->getDestNode(); $id = $node->getId(); - if (isset($checkedNodes[$id])) { - continue; - } - $checkedNodes[$id] = true; - if ($node->getValue() && ($edge->isLazy() || $edge->isWeak())) { // no-op } elseif (isset($currentPath[$id])) { @@ -365,10 +349,11 @@ private function analyzeCircularReferences(array $edges, &$checkedNodes, &$curre $this->circularReferences[$parentId][$id] = $id; $id = $parentId; } - } else { + } elseif (!isset($checkedNodes[$id])) { + $checkedNodes[$id] = true; $currentPath[$id] = $id; $this->analyzeCircularReferences($node->getOutEdges(), $checkedNodes, $currentPath); - array_pop($currentPath); + unset($currentPath[$id]); } } } @@ -428,15 +413,11 @@ private function generateProxyClasses() * * @return string */ - private function addServiceInclude(Definition $definition, array $inlinedDefinitions) + private function addServiceInclude(\SplObjectStorage $inlinedDefinitions) { $template = " require_once %s;\n"; $code = ''; - if (null !== $file = $definition->getFile()) { - $code .= sprintf($template, $this->dumpValue($file)); - } - foreach ($inlinedDefinitions as $definition) { if (null !== $file = $definition->getFile()) { $code .= sprintf($template, $this->dumpValue($file)); @@ -453,40 +434,28 @@ private function addServiceInclude(Definition $definition, array $inlinedDefinit /** * Generates the inline definition of a service. * - * @param string $id - * @param array $inlinedDefinitions - * * @return string * * @throws RuntimeException When the factory definition is incomplete * @throws ServiceCircularReferenceException When a circular reference is detected */ - private function addServiceInlinedDefinitions($id, array $inlinedDefinitions) + private function addServiceInlinedDefinitions($id, Definition $definition, \SplObjectStorage $inlinedDefinitions, &$isSimpleInstance) { $code = ''; $variableMap = $this->definitionVariables; - $nbOccurrences = new \SplObjectStorage(); - $processed = new \SplObjectStorage(); - - foreach ($inlinedDefinitions as $definition) { - if (false === $nbOccurrences->contains($definition)) { - $nbOccurrences->offsetSet($definition, 1); - } else { - $i = $nbOccurrences->offsetGet($definition); - $nbOccurrences->offsetSet($definition, $i + 1); - } - } foreach ($inlinedDefinitions as $sDefinition) { - if ($processed->contains($sDefinition)) { + if ($definition === $sDefinition) { continue; } - $processed->offsetSet($sDefinition); - $class = $this->dumpValue($sDefinition->getClass()); - if ($nbOccurrences->offsetGet($sDefinition) > 1 || $sDefinition->getMethodCalls() || $sDefinition->getProperties() || null !== $sDefinition->getConfigurator() || false !== strpos($class, '$')) { - $name = $this->getNextVariableName(); - $variableMap->offsetSet($sDefinition, new Variable($name)); + if ($inlinedDefinitions[$sDefinition] > 1 || $sDefinition->getMethodCalls() || $sDefinition->getProperties() || $sDefinition->getConfigurator() || false !== strpos($class, '$')) { + if (isset($variableMap[$sDefinition])) { + $name = $variableMap[$sDefinition]; + } else { + $name = $this->getNextVariableName(); + $variableMap[$sDefinition] = new Variable($name); + } // a construct like: // $a = new ServiceA(ServiceB $b); $b = new ServiceB(ServiceA $a); @@ -495,16 +464,18 @@ private function addServiceInlinedDefinitions($id, array $inlinedDefinitions) // $b = new ServiceB(); // $a = new ServiceA(ServiceB $b); // $b->setServiceA(ServiceA $a); - if ($this->hasReference($id, $sDefinition->getArguments())) { + if ($this->hasReference($id, array($sDefinition->getArguments(), $sDefinition->getFactory()))) { throw new ServiceCircularReferenceException($id, array($id)); } $code .= $this->addNewInstance($sDefinition, '$'.$name, ' = ', $id); - if (!$this->hasReference($id, $sDefinition->getMethodCalls(), true) && !$this->hasReference($id, $sDefinition->getProperties(), true)) { + if (!$this->hasReference($id, array($sDefinition->getProperties(), $sDefinition->getMethodCalls(), $sDefinition->getConfigurator()), true)) { $code .= $this->addServiceProperties($sDefinition, $name); $code .= $this->addServiceMethodCalls($sDefinition, $name); $code .= $this->addServiceConfigurator($sDefinition, $name); + } else { + $isSimpleInstance = false; } $code .= "\n"; @@ -559,29 +530,6 @@ private function addServiceInstance($id, Definition $definition, $isSimpleInstan return $code; } - /** - * Checks if the definition is a simple instance. - * - * @param string $id - * @param Definition $definition - * - * @return bool - */ - private function isSimpleInstance($id, Definition $definition, array $inlinedDefinitions) - { - foreach (array_merge(array($definition), $inlinedDefinitions) as $sDefinition) { - if ($definition !== $sDefinition && !$this->hasReference($id, $sDefinition->getMethodCalls())) { - continue; - } - - if ($sDefinition->getMethodCalls() || $sDefinition->getProperties() || $sDefinition->getConfigurator()) { - return false; - } - } - - return true; - } - /** * Checks if the definition is a trivial instance. * @@ -667,27 +615,17 @@ private function addServiceProperties(Definition $definition, $variableName = 'i /** * Generates the inline definition setup. * - * @param string $id - * @param array $inlinedDefinitions - * @param bool $isSimpleInstance - * * @return string * * @throws ServiceCircularReferenceException when the container contains a circular reference */ - private function addServiceInlinedDefinitionsSetup($id, array $inlinedDefinitions, $isSimpleInstance) + private function addServiceInlinedDefinitionsSetup($id, Definition $definition, \SplObjectStorage $inlinedDefinitions, $isSimpleInstance) { $this->referenceVariables[$id] = new Variable('instance'); $code = ''; - $processed = new \SplObjectStorage(); foreach ($inlinedDefinitions as $iDefinition) { - if ($processed->contains($iDefinition)) { - continue; - } - $processed->offsetSet($iDefinition); - - if (!$this->hasReference($id, $iDefinition->getMethodCalls(), true) && !$this->hasReference($id, $iDefinition->getProperties(), true)) { + if ($definition === $iDefinition || !$this->hasReference($id, array($iDefinition->getProperties(), $iDefinition->getMethodCalls(), $iDefinition->getConfigurator()), true)) { continue; } @@ -828,15 +766,28 @@ protected function {$methodName}($lazyInitialization) $code .= sprintf(" @trigger_error(%s, E_USER_DEPRECATED);\n\n", $this->export($definition->getDeprecationMessage($id))); } - $inlinedDefinitions = $this->getInlinedDefinitions($definition); - $isSimpleInstance = $this->isSimpleInstance($id, $definition, $inlinedDefinitions); + $inlinedDefinitions = $this->getInlinedDefinitions(array($definition)); + $constructorDefinitions = $this->getInlinedDefinitions(array($definition->getArguments(), $definition->getFactory())); + $otherDefinitions = new \SplObjectStorage(); + + foreach ($inlinedDefinitions as $def) { + if ($def === $definition || isset($constructorDefinitions[$def])) { + $constructorDefinitions[$def] = $inlinedDefinitions[$def]; + } else { + $otherDefinitions[$def] = $inlinedDefinitions[$def]; + } + } + + $isSimpleInstance = !$definition->getProperties() && !$definition->getMethodCalls() && !$definition->getConfigurator(); $code .= - $this->addServiceInclude($definition, $inlinedDefinitions). - $this->addServiceLocalTempVariables($id, $definition, $inlinedDefinitions). - $this->addServiceInlinedDefinitions($id, $inlinedDefinitions). + $this->addServiceInclude($inlinedDefinitions). + $this->addServiceLocalTempVariables($id, $definition, $constructorDefinitions). + $this->addServiceInlinedDefinitions($id, $definition, $constructorDefinitions, $isSimpleInstance). $this->addServiceInstance($id, $definition, $isSimpleInstance). - $this->addServiceInlinedDefinitionsSetup($id, $inlinedDefinitions, $isSimpleInstance). + $this->addServiceLocalTempVariables($id, $definition, $otherDefinitions). + $this->addServiceInlinedDefinitions($id, $definition, $otherDefinitions, $isSimpleInstance). + $this->addServiceInlinedDefinitionsSetup($id, $definition, $inlinedDefinitions, $isSimpleInstance). $this->addServiceProperties($definition). $this->addServiceMethodCalls($definition). $this->addServiceConfigurator($definition). @@ -1255,8 +1206,7 @@ private function addInlineRequires() foreach ($this->container->findTaggedServiceIds($this->hotPathTag) as $id => $tags) { $definition = $this->container->getDefinition($id); - $inlinedDefinitions = $this->getInlinedDefinitions($definition); - array_unshift($inlinedDefinitions, $definition); + $inlinedDefinitions = $this->getInlinedDefinitions(array($definition)); foreach ($inlinedDefinitions as $iDefinition) { if ($class = is_array($factory = $iDefinition->getFactory()) && is_string($factory[0]) ? $factory[0] : $iDefinition->getClass()) { @@ -1561,47 +1511,30 @@ private function getServiceCallsFromArguments(array $arguments, array &$calls, a } } - /** - * Returns the inline definition. - * - * @return array - */ - private function getInlinedDefinitions(Definition $definition) + private function getInlinedDefinitions(array $arguments, \SplObjectStorage $definitions = null) { - if (false === $this->inlinedDefinitions->contains($definition)) { - $definitions = array_merge( - $this->getDefinitionsFromArguments($definition->getArguments()), - $this->getDefinitionsFromArguments($definition->getMethodCalls()), - $this->getDefinitionsFromArguments($definition->getProperties()), - $this->getDefinitionsFromArguments(array($definition->getConfigurator())), - $this->getDefinitionsFromArguments(array($definition->getFactory())) - ); - - $this->inlinedDefinitions->offsetSet($definition, $definitions); - - return $definitions; + if (null === $definitions) { + $definitions = new \SplObjectStorage(); } - return $this->inlinedDefinitions->offsetGet($definition); - } - - /** - * Gets the definition from arguments. - * - * @return array - */ - private function getDefinitionsFromArguments(array $arguments) - { - $definitions = array(); foreach ($arguments as $argument) { if (is_array($argument)) { - $definitions = array_merge($definitions, $this->getDefinitionsFromArguments($argument)); - } elseif ($argument instanceof Definition) { - $definitions = array_merge( - $definitions, - $this->getInlinedDefinitions($argument), - array($argument) - ); + $this->getInlinedDefinitions($argument, $definitions); + } elseif (!$argument instanceof Definition) { + // no-op + } elseif (isset($definitions[$argument])) { + $definitions[$argument] = 1 + $definitions[$argument]; + } else { + $definitions[$argument] = 1; + $this->getInlinedDefinitions($argument->getArguments(), $definitions); + $this->getInlinedDefinitions(array($argument->getFactory()), $definitions); + $this->getInlinedDefinitions($argument->getProperties(), $definitions); + $this->getInlinedDefinitions($argument->getMethodCalls(), $definitions); + $this->getInlinedDefinitions(array($argument->getConfigurator()), $definitions); + // move current definition last in the list + $nbOccurences = $definitions[$argument]; + unset($definitions[$argument]); + $definitions[$argument] = $nbOccurences; } } @@ -1656,9 +1589,7 @@ private function hasReference($id, array $arguments, $deep = false, array &$visi continue; } - $arguments = array_merge($service->getMethodCalls(), $service->getArguments(), $service->getProperties()); - - if ($this->hasReference($id, $arguments, $deep, $visited)) { + if ($this->hasReference($id, array($service->getArguments(), $service->getFactory(), $service->getProperties(), $service->getMethodCalls(), $service->getConfigurator()), $deep, $visited)) { return true; } } diff --git a/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php b/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php index 0685b9238fbd6..4919a7e02cbaa 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php @@ -1249,24 +1249,24 @@ public function testUninitializedReference() $this->assertEquals(array('foo1' => new \stdClass(), 'foo3' => new \stdClass()), iterator_to_array($bar->iter)); } - public function testAlmostCircularPrivate() + /** + * @dataProvider provideAlmostCircular + */ + public function testAlmostCircular($visibility) { - $public = false; $container = include __DIR__.'/Fixtures/containers/container_almost_circular.php'; $foo = $container->get('foo'); - $this->assertSame($foo, $foo->bar->foobar->foo); + + $foo2 = $container->get('foo2'); + $this->assertSame($foo2, $foo2->bar->foobar->foo); } - public function testAlmostCircularPublic() + public function provideAlmostCircular() { - $public = true; - $container = include __DIR__.'/Fixtures/containers/container_almost_circular.php'; - - $foo = $container->get('foo'); - - $this->assertSame($foo, $foo->bar->foobar->foo); + yield array('public'); + yield array('private'); } public function testRegisterForAutoconfiguration() diff --git a/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php b/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php index 4e8da769f4276..5887ed75cc44e 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php @@ -302,21 +302,6 @@ public function testOverrideServiceWhenUsingADumpedContainer() $this->assertSame($decorator, $container->get('decorator_service'), '->set() overrides an already defined service'); } - /** - * @expectedException \Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException - */ - public function testCircularReference() - { - $container = new ContainerBuilder(); - $container->register('foo', 'stdClass')->addArgument(new Reference('bar'))->setPublic(true); - $container->register('bar', 'stdClass')->setPublic(false)->addMethodCall('setA', array(new Reference('baz'))); - $container->register('baz', 'stdClass')->addMethodCall('setA', array(new Reference('foo')))->setPublic(true); - $container->compile(); - - $dumper = new PhpDumper($container); - $dumper->dump(); - } - public function testDumpAutowireData() { $container = include self::$fixturesPath.'/containers/container24.php'; @@ -774,38 +759,33 @@ public function testUninitializedReference() $this->assertEquals(array('foo1' => new \stdClass(), 'foo3' => new \stdClass()), iterator_to_array($bar->iter)); } - public function testAlmostCircularPrivate() + /** + * @dataProvider provideAlmostCircular + */ + public function testAlmostCircular($visibility) { - $public = false; $container = include self::$fixturesPath.'/containers/container_almost_circular.php'; $container->compile(); $dumper = new PhpDumper($container); - $this->assertStringEqualsFile(self::$fixturesPath.'/php/container_almost_circular_private.php', $dumper->dump(array('class' => 'Symfony_DI_PhpDumper_Test_Almost_Circular_Private'))); + $container = 'Symfony_DI_PhpDumper_Test_Almost_Circular_'.ucfirst($visibility); + $this->assertStringEqualsFile(self::$fixturesPath.'/php/services_almost_circular_'.$visibility.'.php', $dumper->dump(array('class' => $container))); - require self::$fixturesPath.'/php/container_almost_circular_private.php'; + require self::$fixturesPath.'/php/services_almost_circular_'.$visibility.'.php'; - $container = new \Symfony_DI_PhpDumper_Test_Almost_Circular_Private(); - $foo = $container->get('foo'); + $container = new $container(); + $foo = $container->get('foo'); $this->assertSame($foo, $foo->bar->foobar->foo); + + $foo2 = $container->get('foo2'); + $this->assertSame($foo2, $foo2->bar->foobar->foo); } - public function testAlmostCircularPublic() + public function provideAlmostCircular() { - $public = true; - $container = include self::$fixturesPath.'/containers/container_almost_circular.php'; - $container->compile(); - $dumper = new PhpDumper($container); - - $this->assertStringEqualsFile(self::$fixturesPath.'/php/container_almost_circular_public.php', $dumper->dump(array('class' => 'Symfony_DI_PhpDumper_Test_Almost_Circular_Public'))); - - require self::$fixturesPath.'/php/container_almost_circular_public.php'; - - $container = new \Symfony_DI_PhpDumper_Test_Almost_Circular_Public(); - $foo = $container->get('foo'); - - $this->assertSame($foo, $foo->bar->foobar->foo); + yield array('public'); + yield array('private'); } public function testHotPathOptimizations() @@ -815,12 +795,12 @@ public function testHotPathOptimizations() $container->compile(); $dumper = new PhpDumper($container); - $dump = $dumper->dump(array('hot_path_tag' => 'container.hot_path', 'inline_class_loader_parameter' => 'inline_requires', 'file' => self::$fixturesPath.'/php/container_inline_requires.php')); + $dump = $dumper->dump(array('hot_path_tag' => 'container.hot_path', 'inline_class_loader_parameter' => 'inline_requires', 'file' => self::$fixturesPath.'/php/services_inline_requires.php')); if ('\\' === DIRECTORY_SEPARATOR) { $dump = str_replace("'\\\\includes\\\\HotPath\\\\", "'/includes/HotPath/", $dump); } - $this->assertStringEqualsFile(self::$fixturesPath.'/php/container_inline_requires.php', $dump); + $this->assertStringEqualsFile(self::$fixturesPath.'/php/services_inline_requires.php', $dump); } public function testDumpHandlesLiteralClassWithRootNamespace() diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/containers/container_almost_circular.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/containers/container_almost_circular.php index eaef674a3ec5b..2c81a50bc93f5 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/containers/container_almost_circular.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/containers/container_almost_circular.php @@ -5,8 +5,11 @@ use Symfony\Component\DependencyInjection\Dumper\PhpDumper; use Symfony\Component\DependencyInjection\Reference; +$public = 'public' === $visibility; $container = new ContainerBuilder(); +// same visibility for deps + $container->register('foo', FooCircular::class)->setPublic(true) ->addArgument(new Reference('bar')); @@ -16,4 +19,21 @@ $container->register('foobar', FoobarCircular::class)->setPublic($public) ->addArgument(new Reference('foo')); +// mixed visibility for deps + +$container->register('foo2', FooCircular::class)->setPublic(true) + ->addArgument(new Reference('bar2')); + +$container->register('bar2', BarCircular::class)->setPublic(!$public) + ->addMethodCall('addFoobar', array(new Reference('foobar2'))); + +$container->register('foobar2', FoobarCircular::class)->setPublic($public) + ->addArgument(new Reference('foo2')); + +// simple inline setter + +$def = new Definition(FoobarCircular::class); +$container->register('bar3', BarCircular::class)->setPublic(true) + ->addMethodCall('addFoobar', array($def, $def)); + return $container; diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services9_as_files.txt b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services9_as_files.txt index 8c76d4c7636f3..6724846f8dd8e 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services9_as_files.txt +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services9_as_files.txt @@ -33,11 +33,11 @@ use Symfony\Component\DependencyInjection\Argument\RewindableGenerator; // This file has been auto-generated by the Symfony Dependency Injection Component for internal use. // Returns the public 'configured_service' shared service. +$this->services['configured_service'] = $instance = new \stdClass(); + $a = new \ConfClass(); $a->setFoo(${($_ = isset($this->services['baz']) ? $this->services['baz'] : $this->load(__DIR__.'/getBazService.php')) && false ?: '_'}); -$this->services['configured_service'] = $instance = new \stdClass(); - $a->configureStdClass($instance); return $instance; @@ -153,10 +153,10 @@ use Symfony\Component\DependencyInjection\Argument\RewindableGenerator; // This file has been auto-generated by the Symfony Dependency Injection Component for internal use. // Returns the public 'foo_with_inline' shared service. -$a = new \Bar(); - $this->services['foo_with_inline'] = $instance = new \Foo(); +$a = new \Bar(); + $a->pub = 'pub'; $a->setBaz(${($_ = isset($this->services['baz']) ? $this->services['baz'] : $this->load(__DIR__.'/getBazService.php')) && false ?: '_'}); diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services9_compiled.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services9_compiled.php index 403eb12954fe1..ec0db041f4381 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services9_compiled.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services9_compiled.php @@ -129,11 +129,11 @@ protected function getBazService() */ protected function getConfiguredServiceService() { + $this->services['configured_service'] = $instance = new \stdClass(); + $a = new \ConfClass(); $a->setFoo(${($_ = isset($this->services['baz']) ? $this->services['baz'] : $this->getBazService()) && false ?: '_'}); - $this->services['configured_service'] = $instance = new \stdClass(); - $a->configureStdClass($instance); return $instance; @@ -259,10 +259,10 @@ protected function getFooBarService() */ protected function getFooWithInlineService() { - $a = new \Bar(); - $this->services['foo_with_inline'] = $instance = new \Foo(); + $a = new \Bar(); + $a->pub = 'pub'; $a->setBaz(${($_ = isset($this->services['baz']) ? $this->services['baz'] : $this->getBazService()) && false ?: '_'}); diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/container_almost_circular_private.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_almost_circular_private.php similarity index 60% rename from src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/container_almost_circular_private.php rename to src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_almost_circular_private.php index 055f409a5318c..3ece01bc0c6dc 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/container_almost_circular_private.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_almost_circular_private.php @@ -23,7 +23,10 @@ public function __construct() { $this->services = array(); $this->methodMap = array( + 'bar2' => 'getBar2Service', + 'bar3' => 'getBar3Service', 'foo' => 'getFooService', + 'foo2' => 'getFoo2Service', ); $this->aliases = array(); @@ -36,6 +39,7 @@ public function getRemovedIds() 'Symfony\\Component\\DependencyInjection\\ContainerInterface' => true, 'bar' => true, 'foobar' => true, + 'foobar2' => true, ); } @@ -56,6 +60,36 @@ public function isFrozen() return true; } + /** + * Gets the public 'bar2' shared service. + * + * @return \BarCircular + */ + protected function getBar2Service() + { + $this->services['bar2'] = $instance = new \BarCircular(); + + $instance->addFoobar(new \FoobarCircular(${($_ = isset($this->services['foo2']) ? $this->services['foo2'] : $this->getFoo2Service()) && false ?: '_'})); + + return $instance; + } + + /** + * Gets the public 'bar3' shared service. + * + * @return \BarCircular + */ + protected function getBar3Service() + { + $this->services['bar3'] = $instance = new \BarCircular(); + + $a = new \FoobarCircular(); + + $instance->addFoobar($a, $a); + + return $instance; + } + /** * Gets the public 'foo' shared service. * @@ -72,4 +106,20 @@ protected function getFooService() return $instance; } + + /** + * Gets the public 'foo2' shared service. + * + * @return \FooCircular + */ + protected function getFoo2Service() + { + $a = ${($_ = isset($this->services['bar2']) ? $this->services['bar2'] : $this->getBar2Service()) && false ?: '_'}; + + if (isset($this->services['foo2'])) { + return $this->services['foo2']; + } + + return $this->services['foo2'] = new \FooCircular($a); + } } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/container_almost_circular_public.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_almost_circular_public.php similarity index 68% rename from src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/container_almost_circular_public.php rename to src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_almost_circular_public.php index 5c4057d7fa1af..490b8152ac199 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/container_almost_circular_public.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_almost_circular_public.php @@ -24,8 +24,11 @@ public function __construct() $this->services = array(); $this->methodMap = array( 'bar' => 'getBarService', + 'bar3' => 'getBar3Service', 'foo' => 'getFooService', + 'foo2' => 'getFoo2Service', 'foobar' => 'getFoobarService', + 'foobar2' => 'getFoobar2Service', ); $this->aliases = array(); @@ -36,6 +39,7 @@ public function getRemovedIds() return array( 'Psr\\Container\\ContainerInterface' => true, 'Symfony\\Component\\DependencyInjection\\ContainerInterface' => true, + 'bar2' => true, ); } @@ -70,6 +74,22 @@ protected function getBarService() return $instance; } + /** + * Gets the public 'bar3' shared service. + * + * @return \BarCircular + */ + protected function getBar3Service() + { + $this->services['bar3'] = $instance = new \BarCircular(); + + $a = new \FoobarCircular(); + + $instance->addFoobar($a, $a); + + return $instance; + } + /** * Gets the public 'foo' shared service. * @@ -86,6 +106,23 @@ protected function getFooService() return $this->services['foo'] = new \FooCircular($a); } + /** + * Gets the public 'foo2' shared service. + * + * @return \FooCircular + */ + protected function getFoo2Service() + { + $a = new \BarCircular(); + + $this->services['foo2'] = $instance = new \FooCircular($a); + + $a->addFoobar(${($_ = isset($this->services['foobar2']) ? $this->services['foobar2'] : $this->getFoobar2Service()) && false ?: '_'}); + + + return $instance; + } + /** * Gets the public 'foobar' shared service. * @@ -101,4 +138,20 @@ protected function getFoobarService() return $this->services['foobar'] = new \FoobarCircular($a); } + + /** + * Gets the public 'foobar2' shared service. + * + * @return \FoobarCircular + */ + protected function getFoobar2Service() + { + $a = ${($_ = isset($this->services['foo2']) ? $this->services['foo2'] : $this->getFoo2Service()) && false ?: '_'}; + + if (isset($this->services['foobar2'])) { + return $this->services['foobar2']; + } + + return $this->services['foobar2'] = new \FoobarCircular($a); + } } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/container_inline_requires.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_inline_requires.php similarity index 100% rename from src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/container_inline_requires.php rename to src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_inline_requires.php