[DI] Enhance DX by throwing instead of triggering a deprecation notice

This commit is contained in:
Nicolas Grekas 2017-03-27 19:51:07 +02:00
parent d0e904b0da
commit b07da3dc1e
8 changed files with 31 additions and 50 deletions

View File

@ -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:

View File

@ -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:

View File

@ -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;
}

View File

@ -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);

View File

@ -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];

View File

@ -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
*

View File

@ -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;
}

View File

@ -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.