#symfony #dependency-injection
#symfony #внедрение зависимостей
Вопрос:
Я заметил, что служба Symfony запускается только (выполняется конструктор), когда вызывается метод в этой службе. Это может быть важно, если в вашей службе есть только конструктор и нет методов.
Например:
class MyService {
public function __construct($someOtherService) {
$someOtherService->setFoo("bar");
}
}
// And of course put this service in services.yml
app.my_service:
class: AppBundle...MyService
arguments: [ app.some_other_service ]
В этом случае конструктор и, следовательно, setFoo(«bar») не вызывается. Почему это так? Можно ли каким-то образом принудительно инициировать службу, не вызывая (фиктивный) метод в этой службе?
Я также попытался добавить «lazy: false» для app.my_service, но это не имеет никакого значения.
Я использую Symfony 2.8.
Комментарии:
1. Вы что-то неправильно интерпретируете. Конструктор вызывается, как только вы получаете службу из контейнера. Просто определение службы в службах. yml не приводит к созданию экземпляра службы.
2. Да, теперь я понимаю. И я хотел загрузить службу, не получая ее из контейнера.
Ответ №1:
ваши службы никогда не создаются, если они никогда не используются. для принудительного создания службы вы можете подключаться к любому типу прослушивателей событий, который подходит вашему событию, когда вы хотите получить сервис (т.е. kernel.request
) и передать эту службу в качестве зависимости слушателю. это приведет к запуску конструктора службы при первом запуске события в течение срока службы контейнера.
но я бы предпочел предложить вам ознакомиться с архитектурой. наличие службы только с конструктором — это бессмыслица
Более того, вы можете создавать экземпляры служб при создании экземпляра EvendDispatcher
(просто потому, что это будет зависеть от вашей службы) без запуска событий
пример прослушивателя:
class ServiceInstantiatorListener
{
public function onRequest(KernelEvent $kernel)
{
return; //noop, just make sure it works
}
public function instantiate($service)
{
return $service; // noop again, just call to pass service container argument
}
}
конфигурация yaml:
services:
my_app.service_instantiator_listener:
class: MyAppServiceInstantiatorListener
tags:
- { 'name': 'kernel_events', 'event': 'kernel.request', 'method':'onRequest' }
calls:
- [instantiate, ["@my_app.weird_service_one"]]
- [instantiate, ["@my_app.weird_service_two"]]
Идя дальше, вы можете пометить свои службы тегом и динамически настраивать вызовы с MyAppBundleExtension
помощью проходов компилятора
http://symfony.com/doc/current/service_container/tags.html#create-a-compiler-pass
Я надеюсь, что есть лучшие способы принудительно создавать экземпляры сервисов (например, некоторые внутренние события контейнера), но в настоящее время я не встречал случая, когда мне это нужно.
Комментарии:
1. Да! Я уже рассматривал возможность использования прослушивателей событий для поиска решения. Я понимаю, что вы имеете в виду, и обычно я не использую подобные сервисы, но это крайний случай.
2. Спасибо, я использовал ваш пример для этого. Хотя я не использовал «создание экземпляра», но в качестве аргумента я предоставляю контейнер службы, и в слушателе я вызвал обе мои две странные службы 😉
3. Да, но это задерживает создание экземпляра до запуска события, поэтому зависит от того, что вам нужно
Ответ №2:
Вы описываете поведение службы с отложенной загрузкой. Проверьте конфигурацию lazy: true
и удалите / отключите ее.
Symfony docs, служба с отложенной загрузкой:
Фактический класс будет создан, как только вы попытаетесь взаимодействовать со службой (например, вызвать один из ее методов).
Комментарии:
1. Да, я забыл упомянуть, что я уже пытался добавить «lazy: false» для app.my_service, но это не сработало. Я добавлю это в свой пост.
Ответ №3:
На самом деле вам не нужно вызывать фиктивный метод в службе, чтобы инициировать его. Вы можете создать экземпляр объекта service, используя следующий оператор:
$this->container()-> get(‘app.my_service’);
Комментарии:
1. Это я знал, я хотел, чтобы служба загружалась без этого вызова.