Обычная потребность в некоторых приложениях Symfony – использовать неизменяемые сервисы, в то же время используя черты для составления их дополнительных функций. Хотя сервисный контейнер Symfony поддерживает внедрение сеттера, у него есть некоторые недостатки (например, сеттеры могут вызываться не только во время создания, поэтому вы не можете быть уверены, что зависимость не будет заменена в течение времени жизни объекта).
Образцом для решения этой проблемы являются «методы вялости«. Эти методы обычно используют слово with
в качестве префикса своих имен (например, withPropertyName()
), и они возвращают копию экземпляра неизменяемого класса только с одним измененным свойством:
class MyService
{
use LoggerAwareTrait;
// ...
}
trait LoggerAwareTrait
{
private $logger;
public function withLogger(LoggerInterface $logger)
{
$new = clone $this;
$new->logger = $logger;
return $new;
}
}
$service = new MyService();
$service = $service->withLogger($logger);
Это решает наиболее существенные проблемы инъекций сеттера. Вот почему в Symfony 4.3 добавили поддержку «вихревых методов» в сервисный контейнер.
При использовании YAML для настройки служб передайте true
в качестве третьего необязательного параметра вызова метода:
# config/services.yaml
services:
MyService:
# ...
calls:
# the TRUE argument turns this into a wither method
- ['withLogger', ['@logger'], true]
При использовании XML для настройки служб установите для параметра return-clone
значение true
в вызове метода:
<!-- 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="MyService">
<!-- ... -->
<call method="withLogger" returns-clone="true">
<argument type="service" id="logger"/>
</call>
</service>
</services>
</container>
При использовании автосопровождения служб для настройки служб добавьте @return
статическая аннотация PHPdoc
для вихревых методов:
class MyService
{
// ...
/**
* @required
* @return static
*/
public function withLogger(LoggerInterface $logger)
{
// ...
}
}