Обнаружена циклическая зависимость для LazyServiceLoader, например, `UserService`
В Zend Framework 2,
У меня есть класс контроллера UserController
UserController
зависит отUserService
UserService
зависит отUserChangedListener
UserChangedListener
зависит отSomeOtherClass
SomeOtherClass
зависит отUserService
Так вот мой UserController
а также SomeOtherClass
зависят от UserService
,
Я получаю ошибку:
Например, была обнаружена циклическая зависимость для LazyServiceLoader
UserService
Вышеуказанная ошибка (т.е. круговая зависимость для LazyServiceLoader) произошла, когда я вводил SomeOtherClass
в UserChangedListener
И я имею
"zendframework / zend-servicemanager": "^ 2.7.5 || ^ 3.0.3",
UserControllerFactory.php
class UserControllerFactory implements FactoryInterface
{
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
{
$container = $container->getServiceLocator();
return new UserController(
$container->get(UserService::class)
);
}
public function createService(ServiceLocatorInterface $serviceLocator)
{
return $this($serviceLocator, UserController::class);
}
}
UserServiceFactory.php
class UserServiceFactory implements FactoryInterface
{
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
{
$service = new UserService(
$container->get(UserRepository::class)
);
$eventManager = $service->getEventManager();
$eventManager->attach($container->get(UserChangedListener::class));
return $service;
}
public function createService(ServiceLocatorInterface $serviceLocator)
{
return $this($serviceLocator, UserService::class);
}
}
UserChangedListenerFactory.php
class UserChangedListenerFactory implements FactoryInterface
{
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
{
$container = $container->getServiceLocator();
return new UserChangedListener(
$container->get(SomeOtherClass::class)
);
}
public function createService(ServiceLocatorInterface $serviceLocator)
{
return $this($serviceLocator, UserChangedListener::class);
}
}
SomeOtherClassFactory.php
class SomeOtherClassFactory implements FactoryInterface
{
public function createService(ServiceLocatorInterface $serviceLocator)
{
$rootLocator = $serviceLocator->getServiceLocator();
return new SomeOtherClass(
$rootLocator->get(UserService::class)
);
}
}
2 ответа
UserService
зависит отSomeOtherClass
черезUserChangedListener
SomeOtherClass
зависит отUserService
Так что в основном для создания UserService
вам нужно сначала создать SomeOtherClass
экземпляр, но для его создания нужно UserService
экземпляр будет создан уже.
Я не уверен в вашей архитектуре, но в соответствии с именами классов это выглядит немного неправильно, что вы присоединяете UserChangedListener
в UserService
, Наверное UserService
должен только запускать события, и не должен ничего знать о слушателях для этих событий. Но опять же - это просто идея, и для хорошего ответа вам нужно объяснить эти зависимости немного подробнее.
Похоже, у вас есть законная круговая зависимость с UserService
, Сообщение об ошибке говорит вам, что UserService
не может быть создан без UserService
,
Это действительно проблема, представленная хорошей практикой использования внедрения зависимостей через __construct
метод. Таким образом, ZF2 будет загружать в память очень большой объектный граф, когда у вас есть много связанных "сервисов", которые имеют сложные вложенные отношения, у вас обязательно будут круговые зависимости.
ZF2 предлагает Lazy Services в качестве решения для отсрочки создания экземпляров определенных объектов, которые как разработчик вам нужно будет решить, какие из них (я бы предложил UserChangedListener
).
Кроме того, чтобы обновить код, вы можете перенести регистрацию кода слушателя за пределы UserServiceFactory
и в Module::onBootstrap()
метод.
namespace User;
class Module
{
public function onBootstrap(EventInterface $event)
{
$serviceManager = $event->getApplication()->getServiceManager();
// Create the user service first
$userService = $serviceManager->get(UserService::class);
$listener = $serviceManager->get(UserChangedListener::class);
// The create and attach the listener after user service has been created.
$userService->getEventManager()->attach($listener);
}
}
Это будет необходимо, если вы используете "агрегатные" слушатели. Для простых слушателей событий вы также можете использовать SharedEventManager
что позволит избежать накладных расходов на загрузку UserService
в приведенном выше примере.