From b07da3dc1edda6a23a544b6df99ee37b508757d9 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 27 Mar 2017 19:51:07 +0200 Subject: [PATCH] [DI] Enhance DX by throwing instead of triggering a deprecation notice --- UPGRADE-3.3.md | 6 ++++ UPGRADE-4.0.md | 6 ++++ .../Component/DependencyInjection/Alias.php | 7 +--- .../Compiler/ResolveNamedArgumentsPass.php | 8 ++--- .../DependencyInjection/Container.php | 2 -- .../Loader/YamlFileLoader.php | 33 ++++++++----------- .../DependencyInjection/Reference.php | 7 +--- .../Tests/ContainerTest.php | 12 ------- 8 files changed, 31 insertions(+), 50 deletions(-) diff --git a/UPGRADE-3.3.md b/UPGRADE-3.3.md index aeccf911ed..66ebe0f742 100644 --- a/UPGRADE-3.3.md +++ b/UPGRADE-3.3.md @@ -80,6 +80,12 @@ Debug DependencyInjection ------------------- + * [BC BREAK] `_defaults` and `_instanceof` are now reserved service names in Yaml configurations. Please rename any services with that names. + + * [BC BREAK] non-numeric keys in methods and constructors arguments have never been supported and are now forbidden. Please remove them if you happen to have one. + + * Service names that start with an underscore are deprecated in Yaml files and will be reserved in 4.0. Please rename any services with such names. + * Autowiring-types have been deprecated, use aliases instead. Before: diff --git a/UPGRADE-4.0.md b/UPGRADE-4.0.md index ba79eaa80f..e2246364f6 100644 --- a/UPGRADE-4.0.md +++ b/UPGRADE-4.0.md @@ -73,6 +73,12 @@ Debug DependencyInjection ------------------- + * `_defaults` and `_instanceof` are now reserved service names in Yaml configurations. Please rename any services with that names. + + * Non-numeric keys in methods and constructors arguments have never been supported and are now forbidden. Please remove them if you happen to have one. + + * Service names that start with an underscore are now reserved in Yaml files. Please rename any services with such names. + * Autowiring-types have been removed, use aliases instead. Before: diff --git a/src/Symfony/Component/DependencyInjection/Alias.php b/src/Symfony/Component/DependencyInjection/Alias.php index 8eba71973a..a113f8f7f2 100644 --- a/src/Symfony/Component/DependencyInjection/Alias.php +++ b/src/Symfony/Component/DependencyInjection/Alias.php @@ -22,12 +22,7 @@ class Alias */ public function __construct($id, $public = true) { - if (!is_string($id)) { - $type = is_object($id) ? get_class($id) : gettype($id); - $id = (string) $id; - @trigger_error(sprintf('Non-string identifiers are deprecated since Symfony 3.3 and won\'t be supported in 4.0 for Alias to "%s" ("%s" given.) Cast it to string beforehand.', $id, $type), E_USER_DEPRECATED); - } - $this->id = $id; + $this->id = (string) $id; $this->public = $public; } diff --git a/src/Symfony/Component/DependencyInjection/Compiler/ResolveNamedArgumentsPass.php b/src/Symfony/Component/DependencyInjection/Compiler/ResolveNamedArgumentsPass.php index 75ea14a28a..d35775e6d0 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/ResolveNamedArgumentsPass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/ResolveNamedArgumentsPass.php @@ -46,13 +46,13 @@ class ResolveNamedArgumentsPass extends AbstractRecursivePass $resolvedArguments = array(); foreach ($arguments as $key => $argument) { - if (is_int($key) || '' === $key || '$' !== $key[0]) { - if (!is_int($key)) { - @trigger_error(sprintf('Using key "%s" for defining arguments of method "%s" for service "%s" is deprecated since Symfony 3.3 and will throw an exception in 4.0. Use no keys or $named arguments instead.', $key, $method, $this->currentId), E_USER_DEPRECATED); - } + if (is_int($key)) { $resolvedArguments[] = $argument; continue; } + if ('' === $key || '$' !== $key[0]) { + throw new InvalidArgumentException(sprintf('Invalid key "%s" found in arguments of method "%s" for service "%s": only integer or $named arguments are allowed.', $key, $method, $this->currentId)); + } $parameters = null !== $parameters ? $parameters : $this->getParameters($class, $method); diff --git a/src/Symfony/Component/DependencyInjection/Container.php b/src/Symfony/Component/DependencyInjection/Container.php index 7570b4d9d7..05e038ac5c 100644 --- a/src/Symfony/Component/DependencyInjection/Container.php +++ b/src/Symfony/Component/DependencyInjection/Container.php @@ -469,9 +469,7 @@ class Container implements ResettableContainerInterface public function normalizeId($id) { if (!is_string($id)) { - $type = is_object($id) ? get_class($id) : gettype($id); $id = (string) $id; - @trigger_error(sprintf('Non-string service identifiers are deprecated since Symfony 3.3 and won\'t be supported in 4.0 for service "%s" ("%s" given.) Cast it to string beforehand.', $id, $type), E_USER_DEPRECATED); } if (isset($this->normalizedIds[$normalizedId = strtolower($id)])) { $normalizedId = $this->normalizedIds[$normalizedId]; diff --git a/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php b/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php index b05cc92301..8c4df2ed75 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php +++ b/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php @@ -205,10 +205,16 @@ class YamlFileLoader extends FileLoader throw new InvalidArgumentException(sprintf('The "services" key should contain an array in %s. Check your YAML syntax.', $file)); } - if ($this->isUnderscoredParamValid($content, '_instanceof', $file)) { + if (isset($content['services']['_instanceof'])) { + $instanceof = $content['services']['_instanceof']; + unset($content['services']['_instanceof']); + + if (!is_array($instanceof)) { + throw new InvalidArgumentException(sprintf('Service "_instanceof" key must be an array, "%s" given in "%s".', gettype($instanceof), $file)); + } $this->instanceof = array(); $this->isLoadingInstanceof = true; - foreach ($content['services']['_instanceof'] as $id => $service) { + foreach ($instanceof as $id => $service) { if (!$service || !is_array($service)) { throw new InvalidArgumentException(sprintf('Type definition "%s" must be a non-empty array within "_instanceof" in %s. Check your YAML syntax.', $id, $file)); } @@ -217,7 +223,6 @@ class YamlFileLoader extends FileLoader } $this->parseDefinition($id, $service, $file, array()); } - unset($content['services']['_instanceof']); } $this->isLoadingInstanceof = false; @@ -237,13 +242,16 @@ class YamlFileLoader extends FileLoader */ private function parseDefaults(array &$content, $file) { - if (!$this->isUnderscoredParamValid($content, '_defaults', $file)) { + if (!isset($content['services']['_defaults'])) { return array(); } - $defaults = $content['services']['_defaults']; unset($content['services']['_defaults']); + if (!is_array($defaults)) { + throw new InvalidArgumentException(sprintf('Service "_defaults" key must be an array, "%s" given in "%s".', gettype($defaults), $file)); + } + foreach ($defaults as $key => $default) { if (!isset(self::$defaultsKeywords[$key])) { throw new InvalidArgumentException(sprintf('The configuration key "%s" cannot be used to define a default value in "%s". Allowed keys are "%s".', $key, $file, implode('", "', self::$defaultsKeywords))); @@ -281,21 +289,6 @@ class YamlFileLoader extends FileLoader return $defaults; } - private function isUnderscoredParamValid($content, $name, $file) - { - if (!isset($content['services'][$name])) { - return false; - } - - if (!is_array($underscoreParam = $content['services'][$name])) { - throw new InvalidArgumentException(sprintf('Service "%s" key must be an array, "%s" given in "%s".', $name, gettype($underscoreParam), $file)); - } - - // @deprecated condition, to be removed in 4.0 - - return !isset($underscoreParam['alias']) && !isset($underscoreParam['class']) && !isset($underscoreParam['factory']); - } - /** * @param array $service * diff --git a/src/Symfony/Component/DependencyInjection/Reference.php b/src/Symfony/Component/DependencyInjection/Reference.php index ea3467b18b..82906d2b75 100644 --- a/src/Symfony/Component/DependencyInjection/Reference.php +++ b/src/Symfony/Component/DependencyInjection/Reference.php @@ -29,12 +29,7 @@ class Reference */ public function __construct($id, $invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE) { - if (!is_string($id)) { - $type = is_object($id) ? get_class($id) : gettype($id); - $id = (string) $id; - @trigger_error(sprintf('Non-string identifiers are deprecated since Symfony 3.3 and won\'t be supported in 4.0 for Reference to "%s" ("%s" given.) Cast it to string beforehand.', $id, $type), E_USER_DEPRECATED); - } - $this->id = $id; + $this->id = (string) $id; $this->invalidBehavior = $invalidBehavior; } diff --git a/src/Symfony/Component/DependencyInjection/Tests/ContainerTest.php b/src/Symfony/Component/DependencyInjection/Tests/ContainerTest.php index d6cdcec9d2..99419201c6 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/ContainerTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/ContainerTest.php @@ -229,18 +229,6 @@ class ContainerTest extends TestCase $this->assertSame($foo, $sc->get('Foo'), '->get() returns the service for the given id, and converts id to lowercase'); } - /** - * @group legacy - * @expectedDeprecation Non-string service identifiers are deprecated since Symfony 3.3 and won't be supported in 4.0 for service "foo" ("Symfony\Component\DependencyInjection\Alias" given.) Cast it to string beforehand. - * @expectedDeprecation Service identifiers will be made case sensitive in Symfony 4.0. Using "Foo" instead of "foo" is deprecated since version 3.3. - */ - public function testNonStringNormalizeId() - { - $sc = new ProjectServiceContainer(); - $this->assertSame('foo', $sc->normalizeId(new Alias('foo'))); - $this->assertSame('foo', $sc->normalizeId('Foo')); - } - /** * @group legacy * @expectedDeprecation Service identifiers will be made case sensitive in Symfony 4.0. Using "foo" instead of "Foo" is deprecated since version 3.3.