Allowed to define the priority of service decoration
Service decoration is a powerful way to replace some service without actually removing it from the container. This way the new service can make use of the replaced service.
In Symfony 2.8, when more than one service decorate another one, you can define
the priority of each decorator to have a more precise control over them. The new
option is called decoration_priority
, its default value is 0
and the
higher its value, the earlier the decorator is applied:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
services:
app.service1:
class: AppBundle\Service\Service1
app.service2:
class: AppBundle\Service\Service2
arguments: ['@app.service2.inner']
decorates: app.service1
public: false
app.service3:
class: AppBundle\Service\Service3
arguments: ['@app.service3.inner']
decorates: app.service1
decoration_priority: 1
public: false
In the above example, app.service3
is applied first because it defines a
priority of 1
and the priority for app.service2
is 0
(the default
value). Therefore, this config is equivalent to the following PHP code:
1
$this->services['app.service1'] = new Service2(new Service3(new Service1())));
Added logging of unused tags
In Symfony 2.8, when the configuration of a service adds a tag which is not used in the application, a message like this one is logged:
1 2
Tag "this_tag_is_not_used" was defined on service "app.service1" but
was never used.
All the built-in Symfony service tags (such as console.command
and
twig.extension
) have been whitelisted to avoid polluting your log files
with useless messages.
Moreover, if the name of the unused tag is similar to any of the other tags, the log message will add a "Did you mean" section, because this is likely to be a typo in your configuration.
For example, when using the following configuration:
1 2 3 4 5
services:
app.service1:
class: AppBundle\Service\Service1
tags:
- { name: 'kenrel.event_listener', ... }
You'll see the following log message:
1 2
Tag "kenrel.event_listener" was defined on service "app.service1", but
was never used. Did you mean "kernel.event_listener"?
Implemented resettable containers
Symfony 2.8 includes a new ResettableContainerInterface
which defines a
single method called reset()
. This method is useful to release memory when
the container is no longer being used.
Symfony's Kernel class calls this method during the shutdown process:
1 2 3 4 5 6 7 8 9 10
// src/Symfony/Component/HttpKernel/Kernel.php
// ...
public function shutdown()
{
// ...
if ($this->container instanceof ResettableContainerInterface) {
$this->container->reset();
}
}
Symfony's service container implements this interface to remove references to all services during shutdown, improving the odds of destructing services and the container through refcounting rather than waiting for PHP's garbage collector:
1 2 3 4 5 6 7 8
// src/Symfony/Component/DependencyInjection/Container.php
// ...
public function reset()
{
// ...
$this->services = array();
}
Simplified Registering of Compiler Passes
Compiler passes allow to modify the service container while Symfony is compiling it and before being used by the application. In Symfony 2.7 and previous versions, you needed to register those extensions as follows:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
namespace AppBundle;
use Symfony\Component\HttpKernel\Bundle\Bundle;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use AppBundle\DependencyInjection\Compiler\CustomPass;
class AppBundle extends Bundle
{
public function build(ContainerBuilder $container)
{
parent::build($container);
$container->addCompilerPass(new CustomPass());
}
}
In Symfony 2.8, this code is no longer needed because if your extensions
implement CompilerPassInterface
they will be automatically registered and
the process()
method will be executed during the container compilation.
Great! But in my opinion you are forgetting the new
shared
flag in replacement of theprototype
scope.Here's the PR: https://github.com/symfony/symfony/pull/14984
there is a typo:
kenrel -> kernel
here too:
Tag "kenrel.event_listener" was defined on service "app.service1", but
kenrel -> kernel, search for it ;-)
@Oskar Stark The point of the code is to demonstrate the unused tag via a typo.
In the "Simplified Registering of Compiler Passes" section "... because if your extensions implement CompilerPassInterface ..." . Shoudn't that be "... because if your CompilerPasses implement CompilerPassInterface ..."
Malte, no, this works if you DI Bundle Extension implements CompilerPassInterface. See PR if you are not sure https://github.com/symfony/symfony/pull/13761/files
Great!