Skip to content

[DI] Mixing constructor injection and setter injection breaks php dumper #28824

@discordier

Description

@discordier

Symfony version(s) affected: 4.1 (since 4.1.5 - previous not affected)

Description
When having a "complex" service graph consisting a mixture of constructor injection and setter injection, the dumped function in the container will attempt to use a variable before initializing it.

The container will error out with something like:

Notice: Undefined variable: b

How to reproduce
I tried to reduce the amount of involved services to the absolute minimum, this is how far I got it narrowed down.
The following unit test breaks the container dumper on my machine.
Reducing it more, like removing any of the ->addMethodCall() declarations or any of the arguments of multiuse1, will not exhibit the issue anymore.

diff --git a/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php b/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php
index 8cb11568f2..2767fd9847 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php
+++ b/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php
@@ -1071,6 +1071,49 @@ class PhpDumperTest extends TestCase
         $container = new \Symfony_DI_PhpDumper_Errored_Definition();
         $container->get('runtime_error');
     }
+
+    public function testCircularWithAddCalls()
+    {
+        $container = new ContainerBuilder();
+
+        $container
+            ->register('root', 'stdClass')
+            ->setArguments([new Reference('level2'), new Reference('multiuse1')])
+            ->setPublic(true);
+
+        $container
+            ->register('level2', FooForCircularWithAddCalls::class)
+            ->addMethodCall('call', [new Reference('level3')]);
+
+        $container->register('multiuse1', 'stdClass');
+
+        $container
+            ->register('level3', 'stdClass')
+            ->addArgument(new Reference('level4'));
+
+        $container
+            ->register('level4', 'stdClass')
+            ->setArguments([new Reference('multiuse1'), new Reference('level5')]);
+
+        $container
+            ->register('level5', 'stdClass')
+            ->addArgument(new Reference('level6'));
+
+        $container
+            ->register('level6', FooForCircularWithAddCalls::class)
+            ->addMethodCall('call', [new Reference('level5')]);
+
+        $container->compile();
+        $dumper = new PhpDumper($container);
+
+        $content = $dumper->dump(array('class' => 'Symfony_DI_PhpDumper_Test_Circular_With_Add_Calls'));
+
+        eval('?>'.$content);
+
+        $container = new \Symfony_DI_PhpDumper_Test_Circular_With_Add_Calls();
+
+        $this->assertInstanceOf(\stdClass::class, $container->get('root'));
+    }
 }
 
 class Rot13EnvVarProcessor implements EnvVarProcessorInterface
@@ -1096,3 +1139,10 @@ class FooForDeepGraph
         $this->bClone = clone $b;
     }
 }
+
+class FooForCircularWithAddCalls
+{
+    public function call(\stdClass $argument)
+    {
+    }
+}

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions