From a1b14843764ab2168448e54f491c727fab96bed6 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Thu, 11 Jan 2018 08:05:20 +0100 Subject: [PATCH] always call the parent class' constructor --- .../DependencyInjection/Dumper/PhpDumper.php | 23 ++++++-- .../Tests/Dumper/PhpDumperTest.php | 40 +++++++++++++ ...tructorWithMandatoryArgumentsContainer.php | 10 ++++ ...structorWithOptionalArgumentsContainer.php | 10 ++++ .../ConstructorWithoutArgumentsContainer.php | 10 ++++ .../Container/NoConstructorContainer.php | 7 +++ ...er_class_constructor_without_arguments.php | 57 +++++++++++++++++++ ...s_with_mandatory_constructor_arguments.php | 55 ++++++++++++++++++ ...ss_with_optional_constructor_arguments.php | 57 +++++++++++++++++++ ...om_container_class_without_constructor.php | 55 ++++++++++++++++++ 10 files changed, 320 insertions(+), 4 deletions(-) create mode 100644 src/Symfony/Component/DependencyInjection/Tests/Fixtures/Container/ConstructorWithMandatoryArgumentsContainer.php create mode 100644 src/Symfony/Component/DependencyInjection/Tests/Fixtures/Container/ConstructorWithOptionalArgumentsContainer.php create mode 100644 src/Symfony/Component/DependencyInjection/Tests/Fixtures/Container/ConstructorWithoutArgumentsContainer.php create mode 100644 src/Symfony/Component/DependencyInjection/Tests/Fixtures/Container/NoConstructorContainer.php create mode 100644 src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/custom_container_class_constructor_without_arguments.php create mode 100644 src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/custom_container_class_with_mandatory_constructor_arguments.php create mode 100644 src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/custom_container_class_with_optional_constructor_arguments.php create mode 100644 src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/custom_container_class_without_constructor.php diff --git a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php index 4ff85f51b3..2fd3c72fd1 100644 --- a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php +++ b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php @@ -128,6 +128,11 @@ class PhpDumper extends Dumper if (0 !== strpos($baseClass = $options['base_class'], '\\') && 'Container' !== $baseClass) { $baseClass = sprintf('%s\%s', $options['namespace'] ? '\\'.$options['namespace'] : '', $baseClass); + $baseClassWithNamespace = $baseClass; + } elseif ('Container' === $baseClass) { + $baseClassWithNamespace = Container::class; + } else { + $baseClassWithNamespace = $baseClass; } $this->initializeMethodNamesMap('Container' === $baseClass ? Container::class : $baseClass); @@ -169,7 +174,7 @@ class PhpDumper extends Dumper } $code = - $this->startClass($options['class'], $baseClass). + $this->startClass($options['class'], $baseClass, $baseClassWithNamespace). $this->addServices(). $this->addDefaultParametersMethod(). $this->endClass() @@ -917,12 +922,13 @@ EOF; /** * Adds the class headers. * - * @param string $class Class name - * @param string $baseClass The name of the base class + * @param string $class Class name + * @param string $baseClass The name of the base class + * @param string $baseClassWithNamespace Fully qualified base class name * * @return string */ - private function startClass($class, $baseClass) + private function startClass($class, $baseClass, $baseClassWithNamespace) { $bagClass = $this->container->isCompiled() ? 'use Symfony\Component\DependencyInjection\ParameterBag\FrozenParameterBag;' : 'use Symfony\Component\DependencyInjection\ParameterBag\\ParameterBag;'; $namespaceLine = !$this->asFiles && $this->namespace ? "\nnamespace {$this->namespace};\n" : ''; @@ -970,9 +976,18 @@ EOF; } if ($this->container->isCompiled()) { + if (Container::class !== $baseClassWithNamespace) { + $r = $this->container->getReflectionClass($baseClassWithNamespace, false); + + if (null !== $r && (null !== $constructor = $r->getConstructor()) && 0 === $constructor->getNumberOfRequiredParameters()) { + $code .= " parent::__construct();\n\n"; + } + } + if ($this->container->getParameterBag()->all()) { $code .= " \$this->parameters = \$this->getDefaultParameters();\n\n"; } + $code .= " \$this->services = array();\n"; } else { $arguments = $this->container->getParameterBag()->all() ? 'new ParameterBag($this->getDefaultParameters())' : null; diff --git a/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php b/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php index 4a882828a3..f12fc608c9 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php @@ -107,6 +107,46 @@ class PhpDumperTest extends TestCase $this->assertStringEqualsFile(self::$fixturesPath.'/php/services12.php', $dumper->dump(array('file' => __FILE__)), '->dump() dumps __DIR__ relative strings'); } + public function testDumpCustomContainerClassWithoutConstructor() + { + $container = new ContainerBuilder(); + $container->compile(); + + $dumper = new PhpDumper($container); + + $this->assertStringEqualsFile(self::$fixturesPath.'/php/custom_container_class_without_constructor.php', $dumper->dump(array('base_class' => 'NoConstructorContainer', 'namespace' => 'Symfony\Component\DependencyInjection\Tests\Fixtures\Container'))); + } + + public function testDumpCustomContainerClassConstructorWithoutArguments() + { + $container = new ContainerBuilder(); + $container->compile(); + + $dumper = new PhpDumper($container); + + $this->assertStringEqualsFile(self::$fixturesPath.'/php/custom_container_class_constructor_without_arguments.php', $dumper->dump(array('base_class' => 'ConstructorWithoutArgumentsContainer', 'namespace' => 'Symfony\Component\DependencyInjection\Tests\Fixtures\Container'))); + } + + public function testDumpCustomContainerClassWithOptionalArgumentLessConstructor() + { + $container = new ContainerBuilder(); + $container->compile(); + + $dumper = new PhpDumper($container); + + $this->assertStringEqualsFile(self::$fixturesPath.'/php/custom_container_class_with_optional_constructor_arguments.php', $dumper->dump(array('base_class' => 'ConstructorWithOptionalArgumentsContainer', 'namespace' => 'Symfony\Component\DependencyInjection\Tests\Fixtures\Container'))); + } + + public function testDumpCustomContainerClassWithMandatoryArgumentLessConstructor() + { + $container = new ContainerBuilder(); + $container->compile(); + + $dumper = new PhpDumper($container); + + $this->assertStringEqualsFile(self::$fixturesPath.'/php/custom_container_class_with_mandatory_constructor_arguments.php', $dumper->dump(array('base_class' => 'ConstructorWithMandatoryArgumentsContainer', 'namespace' => 'Symfony\Component\DependencyInjection\Tests\Fixtures\Container'))); + } + /** * @dataProvider provideInvalidParameters * @expectedException \InvalidArgumentException diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/Container/ConstructorWithMandatoryArgumentsContainer.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/Container/ConstructorWithMandatoryArgumentsContainer.php new file mode 100644 index 0000000000..ba55fb75d8 --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/Container/ConstructorWithMandatoryArgumentsContainer.php @@ -0,0 +1,10 @@ +services = array(); + + $this->aliases = array(); + } + + public function getRemovedIds() + { + return array( + 'Psr\\Container\\ContainerInterface' => true, + 'Symfony\\Component\\DependencyInjection\\ContainerInterface' => true, + ); + } + + public function compile() + { + throw new LogicException('You cannot compile a dumped container that was already compiled.'); + } + + public function isCompiled() + { + return true; + } + + public function isFrozen() + { + @trigger_error(sprintf('The %s() method is deprecated since Symfony 3.3 and will be removed in 4.0. Use the isCompiled() method instead.', __METHOD__), E_USER_DEPRECATED); + + return true; + } +} diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/custom_container_class_with_mandatory_constructor_arguments.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/custom_container_class_with_mandatory_constructor_arguments.php new file mode 100644 index 0000000000..dd9ed9cbb3 --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/custom_container_class_with_mandatory_constructor_arguments.php @@ -0,0 +1,55 @@ +services = array(); + + $this->aliases = array(); + } + + public function getRemovedIds() + { + return array( + 'Psr\\Container\\ContainerInterface' => true, + 'Symfony\\Component\\DependencyInjection\\ContainerInterface' => true, + ); + } + + public function compile() + { + throw new LogicException('You cannot compile a dumped container that was already compiled.'); + } + + public function isCompiled() + { + return true; + } + + public function isFrozen() + { + @trigger_error(sprintf('The %s() method is deprecated since Symfony 3.3 and will be removed in 4.0. Use the isCompiled() method instead.', __METHOD__), E_USER_DEPRECATED); + + return true; + } +} diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/custom_container_class_with_optional_constructor_arguments.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/custom_container_class_with_optional_constructor_arguments.php new file mode 100644 index 0000000000..d65ac7dfbc --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/custom_container_class_with_optional_constructor_arguments.php @@ -0,0 +1,57 @@ +services = array(); + + $this->aliases = array(); + } + + public function getRemovedIds() + { + return array( + 'Psr\\Container\\ContainerInterface' => true, + 'Symfony\\Component\\DependencyInjection\\ContainerInterface' => true, + ); + } + + public function compile() + { + throw new LogicException('You cannot compile a dumped container that was already compiled.'); + } + + public function isCompiled() + { + return true; + } + + public function isFrozen() + { + @trigger_error(sprintf('The %s() method is deprecated since Symfony 3.3 and will be removed in 4.0. Use the isCompiled() method instead.', __METHOD__), E_USER_DEPRECATED); + + return true; + } +} diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/custom_container_class_without_constructor.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/custom_container_class_without_constructor.php new file mode 100644 index 0000000000..4cf1ae40b4 --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/custom_container_class_without_constructor.php @@ -0,0 +1,55 @@ +services = array(); + + $this->aliases = array(); + } + + public function getRemovedIds() + { + return array( + 'Psr\\Container\\ContainerInterface' => true, + 'Symfony\\Component\\DependencyInjection\\ContainerInterface' => true, + ); + } + + public function compile() + { + throw new LogicException('You cannot compile a dumped container that was already compiled.'); + } + + public function isCompiled() + { + return true; + } + + public function isFrozen() + { + @trigger_error(sprintf('The %s() method is deprecated since Symfony 3.3 and will be removed in 4.0. Use the isCompiled() method instead.', __METHOD__), E_USER_DEPRECATED); + + return true; + } +}