Service Method Calls and Setter Injection¶
ちなみに
If you’re using autowiring, you can use @required
to
automatically configure method calls.
Usually, you’ll want to inject your dependencies via the constructor. But sometimes, especially if a dependency is optional, you may want to use “setter injection”. For example:
namespace App\Service;
use Psr\Log\LoggerInterface;
class MessageGenerator
{
private $logger;
public function setLogger(LoggerInterface $logger)
{
$this->logger = $logger;
}
// ...
}
To configure the container to call the setLogger
method, use the calls
key:
- YAML
1 2 3 4 5 6
# config/services.yaml services: App\Service\MessageGenerator: # ... calls: - [setLogger, ['@logger']]
- XML
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
<!-- config/services.xml --> <?xml version="1.0" encoding="UTF-8" ?> <container xmlns="http://symfony.com/schema/dic/services" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/dic/services https://symfony.com/schema/dic/services/services-1.0.xsd"> <services> <service id="App\Service\MessageGenerator"> <!-- ... --> <call method="setLogger"> <argument type="service" id="logger"/> </call> </service> </services> </container>
- PHP
1 2 3 4 5 6 7 8 9 10 11
// config/services.php namespace Symfony\Component\DependencyInjection\Loader\Configurator; use App\Service\MessageGenerator; return function(ContainerConfigurator $configurator) { // ... $services->set(MessageGenerator::class) ->call('setLogger', [ref('logger')]); };
To provide immutable services, some classes implement immutable setters. Such setters return a new instance of the configured class instead of mutating the object they were called on:
namespace App\Service;
use Psr\Log\LoggerInterface;
class MessageGenerator
{
private $logger;
/**
* @return static
*/
public function withLogger(LoggerInterface $logger)
{
$new = clone $this;
$new->logger = $logger;
return $new;
}
// ...
}
Because the method returns a separate cloned instance, configuring such a service means using
the return value of the wither method ($service = $service->withLogger($logger);
).
The configuration to tell the container it should do so would be like:
- YAML
1 2 3 4 5 6
# config/services.yaml services: App\Service\MessageGenerator: # ... calls: - withLogger: !returns_clone ['@logger']
- XML
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
<!-- config/services.xml --> <?xml version="1.0" encoding="UTF-8" ?> <container xmlns="http://symfony.com/schema/dic/services" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/dic/services https://symfony.com/schema/dic/services/services-1.0.xsd"> <services> <service id="App\Service\MessageGenerator"> <!-- ... --> <call method="withLogger" returns-clone="true"> <argument type="service" id="logger"/> </call> </service> </services> </container>
- PHP
1 2 3 4 5 6
// config/services.php use App\Service\MessageGenerator; use Symfony\Component\DependencyInjection\Reference; $container->register(MessageGenerator::class) ->addMethodCall('withLogger', [new Reference('logger')], true);