Обнаружена циклическая зависимость для 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 в приведенном выше примере.

Другие вопросы по тегам