Skip to content

Commit 2454a4f

Browse files
feature symfony#23712 [DependencyInjection] Deprecate autowiring service auto-registration (GuilhemN)
This PR was squashed before being merged into the 3.4 branch (closes symfony#23712). Discussion ---------- [DependencyInjection] Deprecate autowiring service auto-registration | Q | A | ------------- | --- | Branch? | 3.4 | Bug fix? | no | New feature? | no <!-- don't forget updating src/**/CHANGELOG.md files --> | BC breaks? | no | Deprecations? | yes <!-- don't forget updating UPGRADE-*.md files --> | Tests pass? | yes | Fixed tickets | symfony#23350 | License | MIT | Doc PR | Fix symfony#23350, to make autowiring more predictable. Commits ------- 969a207 [DependencyInjection] Deprecate autowiring service auto-registration
2 parents 4860b3e + 969a207 commit 2454a4f

File tree

7 files changed

+129
-19
lines changed

7 files changed

+129
-19
lines changed

UPGRADE-3.4.md

Lines changed: 51 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,50 @@ UPGRADE FROM 3.3 to 3.4
44
DependencyInjection
55
-------------------
66

7+
* Relying on service auto-registration while autowiring is deprecated and won't be supported
8+
in Symfony 4.0. Explicitly inject your dependencies or create services
9+
whose ids are their fully-qualified class name.
10+
11+
Before:
12+
13+
```php
14+
namespace App\Controller;
15+
16+
use App\Mailer;
17+
18+
class DefaultController
19+
{
20+
public function __construct(Mailer $mailer) {
21+
// ...
22+
}
23+
24+
// ...
25+
}
26+
```
27+
```yml
28+
services:
29+
App\Controller\DefaultController:
30+
autowire: true
31+
```
32+
33+
After:
34+
35+
```php
36+
// same PHP code
37+
```
38+
```yml
39+
services:
40+
App\Controller\DefaultController:
41+
autowire: true
42+
43+
# or
44+
# App\Controller\DefaultController:
45+
# arguments: { $mailer: "@App\Mailer" }
46+
47+
App\Mailer:
48+
autowire: true
49+
```
50+
751
* Top-level anonymous services in XML are deprecated and will throw an exception in Symfony 4.0.
852
953
Debug
@@ -37,13 +81,13 @@ FrameworkBundle
3781
require symfony/stopwatch` in your `dev` environment.
3882

3983
* Using the `KERNEL_DIR` environment variable or the automatic guessing based
40-
on the `phpunit.xml` / `phpunit.xml.dist` file location is deprecated since 3.4.
84+
on the `phpunit.xml` / `phpunit.xml.dist` file location is deprecated since 3.4.
4185
Set the `KERNEL_CLASS` environment variable to the fully-qualified class name
42-
of your Kernel instead. Not setting the `KERNEL_CLASS` environment variable
43-
will throw an exception on 4.0 unless you override the `KernelTestCase::createKernel()`
86+
of your Kernel instead. Not setting the `KERNEL_CLASS` environment variable
87+
will throw an exception on 4.0 unless you override the `KernelTestCase::createKernel()`
4488
or `KernelTestCase::getKernelClass()` method.
45-
46-
* The `KernelTestCase::getPhpUnitXmlDir()` and `KernelTestCase::getPhpUnitCliConfigArgument()`
89+
90+
* The `KernelTestCase::getPhpUnitXmlDir()` and `KernelTestCase::getPhpUnitCliConfigArgument()`
4791
methods are deprecated since 3.4 and will be removed in 4.0.
4892

4993
* The `--no-prefix` option of the `translation:update` command is deprecated and
@@ -90,7 +134,7 @@ TwigBridge
90134
* deprecated the `Symfony\Bridge\Twig\Form\TwigRenderer` class, use the `FormRenderer`
91135
class from the Form component instead
92136

93-
* deprecated `Symfony\Bridge\Twig\Command\DebugCommand::set/getTwigEnvironment` and the ability
137+
* deprecated `Symfony\Bridge\Twig\Command\DebugCommand::set/getTwigEnvironment` and the ability
94138
to pass a command name as first argument
95139

96140
* deprecated `Symfony\Bridge\Twig\Command\LintCommand::set/getTwigEnvironment` and the ability
@@ -102,7 +146,7 @@ TwigBundle
102146
* deprecated the `Symfony\Bundle\TwigBundle\Command\DebugCommand` class, use the `DebugCommand`
103147
class from the Twig bridge instead
104148

105-
* deprecated relying on the `ContainerAwareInterface` implementation for
149+
* deprecated relying on the `ContainerAwareInterface` implementation for
106150
`Symfony\Bundle\TwigBundle\Command\LintCommand`
107151

108152
Validator

UPGRADE-4.0.md

Lines changed: 49 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,50 @@ Debug
7777
DependencyInjection
7878
-------------------
7979

80+
* Relying on service auto-registration while autowiring is not supported anymore.
81+
Explicitly inject your dependencies or create services whose ids are
82+
their fully-qualified class name.
83+
84+
Before:
85+
86+
```php
87+
namespace App\Controller;
88+
89+
use App\Mailer;
90+
91+
class DefaultController
92+
{
93+
public function __construct(Mailer $mailer) {
94+
// ...
95+
}
96+
97+
// ...
98+
}
99+
```
100+
```yml
101+
services:
102+
App\Controller\DefaultController:
103+
autowire: true
104+
```
105+
106+
After:
107+
108+
```php
109+
// same PHP code
110+
```
111+
```yml
112+
services:
113+
App\Controller\DefaultController:
114+
autowire: true
115+
116+
# or
117+
# App\Controller\DefaultController:
118+
# arguments: { $mailer: "@App\Mailer" }
119+
120+
App\Mailer:
121+
autowire: true
122+
```
123+
80124
* Autowiring services based on the types they implement is not supported anymore. Rename (or alias) your services to their FQCN id to make them autowirable.
81125
82126
* `_defaults` and `_instanceof` are now reserved service names in Yaml configurations. Please rename any services with that names.
@@ -345,9 +389,9 @@ FrameworkBundle
345389
class instead.
346390

347391
* Using the `KERNEL_DIR` environment variable and the automatic guessing based
348-
on the `phpunit.xml` file location have been removed from the `KernelTestCase::getKernelClass()`
392+
on the `phpunit.xml` file location have been removed from the `KernelTestCase::getKernelClass()`
349393
method implementation. Set the `KERNEL_CLASS` environment variable to the
350-
fully-qualified class name of your Kernel or override the `KernelTestCase::createKernel()`
394+
fully-qualified class name of your Kernel or override the `KernelTestCase::createKernel()`
351395
or `KernelTestCase::getKernelClass()` method instead.
352396

353397
* The `Symfony\Bundle\FrameworkBundle\Validator\ConstraintValidatorFactory` class has been removed.
@@ -356,10 +400,10 @@ FrameworkBundle
356400
* The `--no-prefix` option of the `translation:update` command has
357401
been removed.
358402

359-
* The `Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddCacheClearerPass` class has been removed.
403+
* The `Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddCacheClearerPass` class has been removed.
360404
Use the `Symfony\Component\HttpKernel\DependencyInjection\AddCacheClearerPass` class instead.
361405

362-
* The `Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddCacheWarmerPass` class has been removed.
406+
* The `Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddCacheWarmerPass` class has been removed.
363407
Use the `Symfony\Component\HttpKernel\DependencyInjection\AddCacheWarmerPass` class instead.
364408

365409
* The `Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\TranslationDumperPass`
@@ -561,7 +605,7 @@ TwigBridge
561605
* The `TwigRendererEngine::setEnvironment()` method has been removed.
562606
Pass the Twig Environment as second argument of the constructor instead.
563607

564-
* Removed `Symfony\Bridge\Twig\Command\DebugCommand::set/getTwigEnvironment` and the ability
608+
* Removed `Symfony\Bridge\Twig\Command\DebugCommand::set/getTwigEnvironment` and the ability
565609
to pass a command name as first argument.
566610

567611
* Removed `Symfony\Bridge\Twig\Command\LintCommand::set/getTwigEnvironment` and the ability

src/Symfony/Component/DependencyInjection/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ CHANGELOG
44
3.4.0
55
-----
66

7+
* deprecated service auto-registration while autowiring
78
* deprecated the ability to check for the initialization of a private service with the `Container::initialized()` method
89
* deprecated support for top-level anonymous services in XML
910

src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -477,6 +477,8 @@ private function createAutowiredDefinition($type)
477477
$this->currentId = $currentId;
478478
}
479479

480+
@trigger_error(sprintf('Relying on service auto-registration for type "%s" is deprecated since version 3.4 and won\'t be supported in 4.0. Create a service named "%s" instead.', $type, $type), E_USER_DEPRECATED);
481+
480482
$this->container->log($this, sprintf('Type "%s" has been auto-registered for service "%s".', $type, $this->currentId));
481483

482484
return new TypedReference($argumentId, $type);

src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,11 @@ public function testWithTypeSet()
287287
$this->assertEquals(CollisionInterface::class, (string) $container->getDefinition('a')->getArgument(0));
288288
}
289289

290+
/**
291+
* @group legacy
292+
* @expectedDeprecation Relying on service auto-registration for type "Symfony\Component\DependencyInjection\Tests\Compiler\Lille" is deprecated since version 3.4 and won't be supported in 4.0. Create a service named "Symfony\Component\DependencyInjection\Tests\Compiler\Lille" instead.
293+
* @expectedDeprecation Relying on service auto-registration for type "Symfony\Component\DependencyInjection\Tests\Compiler\Dunglas" is deprecated since version 3.4 and won't be supported in 4.0. Create a service named "Symfony\Component\DependencyInjection\Tests\Compiler\Dunglas" instead.
294+
*/
290295
public function testCreateDefinition()
291296
{
292297
$container = new ContainerBuilder();
@@ -368,6 +373,8 @@ public function testClassNotFoundThrowsException()
368373
$aDefinition = $container->register('a', __NAMESPACE__.'\BadTypeHintedArgument');
369374
$aDefinition->setAutowired(true);
370375

376+
$container->register(Dunglas::class, Dunglas::class);
377+
371378
$pass = new AutowirePass();
372379
$pass->process($container);
373380
}
@@ -383,6 +390,8 @@ public function testParentClassNotFoundThrowsException()
383390
$aDefinition = $container->register('a', __NAMESPACE__.'\BadParentTypeHintedArgument');
384391
$aDefinition->setAutowired(true);
385392

393+
$container->register(Dunglas::class, Dunglas::class);
394+
386395
$pass = new AutowirePass();
387396
$pass->process($container);
388397
}
@@ -595,6 +604,10 @@ public function testExplicitMethodInjection()
595604
);
596605
}
597606

607+
/**
608+
* @group legacy
609+
* @expectedDeprecation Relying on service auto-registration for type "Symfony\Component\DependencyInjection\Tests\Compiler\A" is deprecated since version 3.4 and won't be supported in 4.0. Create a service named "Symfony\Component\DependencyInjection\Tests\Compiler\A" instead.
610+
*/
598611
public function testTypedReference()
599612
{
600613
$container = new ContainerBuilder();
@@ -653,6 +666,8 @@ public function testIgnoreServiceWithClassNotExisting()
653666
$barDefinition = $container->register('bar', __NAMESPACE__.'\Bar');
654667
$barDefinition->setAutowired(true);
655668

669+
$container->register(Foo::class, Foo::class);
670+
656671
$pass = new AutowirePass();
657672
$pass->process($container);
658673

src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
use Symfony\Component\DependencyInjection\Definition;
2929
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
3030
use Symfony\Component\DependencyInjection\ServiceLocator;
31+
use Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition;
3132
use Symfony\Component\DependencyInjection\Tests\Fixtures\TestServiceSubscriber;
3233
use Symfony\Component\DependencyInjection\Variable;
3334
use Symfony\Component\ExpressionLanguage\Expression;
@@ -560,6 +561,9 @@ public function testServiceSubscriber()
560561
))
561562
;
562563
$container->register(TestServiceSubscriber::class, TestServiceSubscriber::class);
564+
565+
$container->register(CustomDefinition::class, CustomDefinition::class)
566+
->setPublic(false);
563567
$container->compile();
564568

565569
$dumper = new PhpDumper($container);

src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_subscriber.php

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,16 +28,16 @@ public function __construct()
2828
{
2929
$this->services = array();
3030
$this->normalizedIds = array(
31-
'autowired.symfony\\component\\dependencyinjection\\tests\\fixtures\\customdefinition' => 'autowired.Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\CustomDefinition',
31+
'symfony\\component\\dependencyinjection\\tests\\fixtures\\customdefinition' => 'Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\CustomDefinition',
3232
'symfony\\component\\dependencyinjection\\tests\\fixtures\\testservicesubscriber' => 'Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\TestServiceSubscriber',
3333
);
3434
$this->methodMap = array(
35+
'Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\CustomDefinition' => 'getCustomDefinitionService',
3536
'Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\TestServiceSubscriber' => 'getTestServiceSubscriberService',
36-
'autowired.Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\CustomDefinition' => 'getCustomDefinitionService',
3737
'foo_service' => 'getFooServiceService',
3838
);
3939
$this->privates = array(
40-
'autowired.Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\CustomDefinition' => true,
40+
'Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\CustomDefinition' => true,
4141
);
4242

4343
$this->aliases = array();
@@ -87,23 +87,23 @@ protected function getTestServiceSubscriberService()
8787
protected function getFooServiceService()
8888
{
8989
return $this->services['foo_service'] = new \Symfony\Component\DependencyInjection\Tests\Fixtures\TestServiceSubscriber(new \Symfony\Component\DependencyInjection\ServiceLocator(array('Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\CustomDefinition' => function () {
90-
$f = function (\Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition $v) { return $v; }; return $f(${($_ = isset($this->services['autowired.Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition']) ? $this->services['autowired.Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition'] : $this->getCustomDefinitionService()) && false ?: '_'});
90+
$f = function (\Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition $v = null) { return $v; }; return $f(${($_ = isset($this->services['Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition']) ? $this->services['Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition'] : $this->getCustomDefinitionService()) && false ?: '_'});
9191
}, 'Symfony\\Component\\DependencyInjection\\Tests\\Fixtures\\TestServiceSubscriber' => function () {
9292
$f = function (\Symfony\Component\DependencyInjection\Tests\Fixtures\TestServiceSubscriber $v) { return $v; }; return $f(${($_ = isset($this->services['Symfony\Component\DependencyInjection\Tests\Fixtures\TestServiceSubscriber']) ? $this->services['Symfony\Component\DependencyInjection\Tests\Fixtures\TestServiceSubscriber'] : $this->get('Symfony\Component\DependencyInjection\Tests\Fixtures\TestServiceSubscriber')) && false ?: '_'});
9393
}, 'bar' => function () {
9494
$f = function (\Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition $v) { return $v; }; return $f(${($_ = isset($this->services['Symfony\Component\DependencyInjection\Tests\Fixtures\TestServiceSubscriber']) ? $this->services['Symfony\Component\DependencyInjection\Tests\Fixtures\TestServiceSubscriber'] : $this->get('Symfony\Component\DependencyInjection\Tests\Fixtures\TestServiceSubscriber')) && false ?: '_'});
9595
}, 'baz' => function () {
96-
$f = function (\Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition $v) { return $v; }; return $f(${($_ = isset($this->services['autowired.Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition']) ? $this->services['autowired.Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition'] : $this->getCustomDefinitionService()) && false ?: '_'});
96+
$f = function (\Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition $v = null) { return $v; }; return $f(${($_ = isset($this->services['Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition']) ? $this->services['Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition'] : $this->getCustomDefinitionService()) && false ?: '_'});
9797
})));
9898
}
9999

100100
/**
101-
* Gets the private 'autowired.Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition' shared autowired service.
101+
* Gets the private 'Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition' shared service.
102102
*
103103
* @return \Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition
104104
*/
105105
protected function getCustomDefinitionService()
106106
{
107-
return $this->services['autowired.Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition'] = new \Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition();
107+
return $this->services['Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition'] = new \Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition();
108108
}
109109
}

0 commit comments

Comments
 (0)