php ZF2 何时使用 getServiceLocator() 何时不使用

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14911965/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-25 08:11:18  来源:igfitidea点击:

ZF2 when to use getServiceLocator() and when not to

phpframeworkszend-framework2service-locator

提问by machete

I am really confused on when to use getServiceLocator and when not to. As an example:

我真的很困惑何时使用 getServiceLocator 何时不使用。举个例子:

+ Module
-+ Helloworld
--+ src
---+ Controller
----+ IndexController.php
----+ IndexControllerFactory.php

---+ Service
----+ LogginService.php
----+ GreetingService.php
----+ GreetingServiceFactory.php

GreetingServiceFactory.php has the content:

GreetingServiceFactory.php 有以下内容:

<?php
namespace Helloworld\Service;

use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;


class GreetingServiceFactory implements FactoryInterface
{

    public function createService (ServiceLocatorInterface $serviceLocator)
    {
        $greetingService = new GreetingService();

        $greetingService->setEventManager($serviceLocator->get('eventManager'));

        $loggingService = $serviceLocator->get('loggingService');

        $greetingService->getEventManager()->attach('getGreeting', array(
            $loggingService,
            'onGetGreeting'
        ));

        return $greetingService;
    }
}

And IndexControllerFactory.php has the content:

和 IndexControllerFactory.php 有内容:

<?php
namespace Helloworld\Controller;

use Zend\ServiceManager\FactoryInterface;
use Zend\ServiceManager\ServiceLocatorInterface;

class IndexControllerFactory implements FactoryInterface
{

    public function createService (ServiceLocatorInterface $serviceLocator)
    {
        $ctr = new IndexController();

        $ctr->setGreetingService($serviceLocator->getServiceLocator()
            ->get('greetingService'));
        return $ctr;
    }
}

As you can see, I need $serviceLocator->getServiceLocator() in my ControllerFactory but not in my ServiceFactory. Why? Both use the same interface ServiceLocatorInterface which does not even define the getServiceLocator() method.

如您所见,我的 ControllerFactory 中需要 $serviceLocator->getServiceLocator(),但 ServiceFactory 中不需要。为什么?两者都使用相同的接口 ServiceLocatorInterface,它甚至没有定义 getServiceLocator() 方法。

module.config.php:

模块.config.php:

'controllers' => array(
    'factories' => array(
        'Helloworld\Controller\Index' => 'Helloworld\Controller\IndexControllerFactory'
    )
)
,
'service_manager' => array(
    'invokables' => array(
        'loggingService' => 'Helloworld\Service\LoggingService'
    ),
    'factories' => array(
        'greetingService'=> 'Helloworld\Service\GreetingServiceFactory'
    ),
)

I'd appreciate any clarification :)

我很感激任何澄清:)

Have a nice day!

祝你今天过得愉快!

回答by Ocramius

The method getServiceLocatoris defined on the AbstractPluginManager, since it implements the ServiceLocatorAwareInterface. As Maks3w pointed out, it is not part of the ServiceLocatorInterface, so avoid using it when implementing a service factory.

该方法getServiceLocator在 上定义AbstractPluginManager,因为它实现了ServiceLocatorAwareInterface。正如 Maks3w 所指出的,它不是 的一部分ServiceLocatorInterface,因此在实现服务工厂时避免使用它。

You can anyway define your factory as closure and still use it:

无论如何,您可以将工厂定义为闭包并仍然使用它:

class MyModule
{
    public function getControllerConfig()
    {
        return array(
            'factories' => array(
                'IndexController' => function (
                    \Zend\ServiceManager\AbstractPluginManager $pm
                ) {
                    $ctr = new IndexController();

                    $ctr->setGreetingService(
                        $pm
                            ->getServiceLocator()
                            ->get('greetingService')
                    );

                    return $ctr;
                },
            ),
        );
    }
}

While in this example $pmis indeed a ServiceLocatorInterfaceinstance, you will still need to get a reference to the "main" service manager to access the 'greetingService'.

虽然在这个例子$pm中确实是一个ServiceLocatorInterface实例,但您仍然需要获得对“主”服务管理器的引用才能访问'greetingService'.

ZF2 uses different service managers or plugin managers for controllers, services, view helpers, controller plugins, etc... That is mainly for type-hinting (look at the interface of the AbstractPluginManagerto understand how type strictness is achieved) and for security.

ZF2 为控制器、服务、视图助手、控制器插件等使用不同的服务管理器或插件管理器……这主要是为了类型提示(查看接口AbstractPluginManager以了解如何实现类型严格性)和安全性。

In this case, the security issue is disallowing access to services that are not controllers, especially with routes with a dynamic controllerparameter. That's why controllers are kept in a separate plugin manager.

在这种情况下,安全问题是不允许访问非控制器的服务,尤其是带有动态controller参数的路由。这就是控制器保存在单独的插件管理器中的原因。

Since the controller plugin manager is created from the "main" service manager, it also is initialized thanks to the ServiceLocatorAwareInterface.

由于控制器插件管理器是从“主”服务管理器创建的,因此它也通过ServiceLocatorAwareInterface.

To make this more clear, I've added a graph of the relations (does not include the factory and don't take it as valid UML):

为了更清楚地说明这一点,我添加了关系图(不包括工厂,也不将其视为有效的 UML):

Pseudo-UML

伪UML

回答by Rob Allen

As you can see, I need $serviceLocator->getServiceLocator() in my ControllerFactory but not in my ServiceFactory. Why?

如您所见,我的 ControllerFactory 中需要 $serviceLocator->getServiceLocator(),但 ServiceFactory 中不需要。为什么?

The controller factory is called by a different service manager instance (the "ControllerLoader") to the main one. This is so that the dispatcher can't result in an arbitrary class being instantiated by the main service manager.

控制器工厂由与主实例不同的服务管理器实例(“ControllerLoader”)调用。这样调度器就不会导致主服务管理器实例化任意类。

As a result, the controller factory's $serviceLocator is not the one you need when you want to retrieve 'greetingService', as 'greetingService' is registered with the main service manager. To get the main server manager from the controller one, you use getServiceLocator() and you now have an instance of the main service manager from which you can get() 'greeting service'

因此,当您想要检索 'greetingService' 时,控制器工厂的 $serviceLocator 不是您需要的,因为 'greetingService' 已在主服务管理器中注册。要从控制器中获取主服务器管理器,您可以使用 getServiceLocator() 并且您现在拥有主服务管理器的一个实例,您可以从中获取 () '问候服务'

This is known as 'peering'. i.e. the "ControllerLoader" service manager (the one configured via the 'controllers' key in the config or getControllerConfiguration() in a Module class) is set up with the main service manager as a peer.

这称为“对等互连”。即,“ControllerLoader”服务管理器(通过配置中的“controllers”键或模块类中的 getControllerConfiguration() 配置的服务管理器)与主服务管理器一起设置为对等体。

回答by Maks3w

Denitively you shouln't use getServiceLocatorsince that method is not defined in ServiceLocatorInterfaceinstead use get()

肯定地,您不应该使用,getServiceLocator因为该方法未定义为ServiceLocatorInterface而是使用get()

回答by jumpinHyman

I am offering this up as an alternative that uses the base module.config.php setup

我提供它作为使用基本 module.config.php 设置的替代方案

Now I was doing something similar but using something like this.

现在我正在做类似的事情,但使用类似的东西。

class BaseServices extends AbstractActionController
implements ServiceLocatorAwareInterface{
    ...
  public function setServiceLocator(ServiceLocatorInterface $serviceLocator){
        if($serviceLocator instanceof ControllerManager){
          $this->service_locator = $serviceLocator->getServiceLocator();

          $this->entities_service = $this->service_locator
            ->get('entities_service');

          $this->session = new Session(array(
            'entities_service'=>$this->entities_service,
            'service_locator'=>$this->service_locator,
          ));
          return $this;
        }
      }
  }
...
}

Now the thing that had stumped me was having to come to the realization that I needed to only use the first service locator that is used during the instantiation of any controller that extends this class...

现在困扰我的事情是不得不意识到我只需要使用在扩展此类的任何控制器的实例化期间使用的第一个服务定位器......

On instantiation: this class was first getting fed a ControllerManager and then the ServiceManager for the setServiceLocator method.

在实例化时:这个类首先得到一个 ControllerManager,然后是 setServiceLocator 方法的 ServiceManager。

I only wanted to use the ControllerManger and its method for getting the ServiceManager to then instantiate my factories;

我只想使用 ControllerManger 及其方法来获取 ServiceManager 然后实例化我的工厂;

the partial on my module.config.php

我的 module.config.php 上的部分

module.config.php
{
...
'service_manager' =>
  'abstract_factories' => array(
    'Zend\Log\LoggerAbstractServiceFactory',
   ),
  'factories' => array(
       'entities_service' => 'Service\Providers\Entities',
  ),
   'invokables' => array(
     'post'      => 'Service\Controllers\Runtime\Post',
    ),
  ),
}

Now I could have used something like the following to filter for the right ServiceLocator... yet I am a fan of using as little boiler plate as necessary...

现在我可以使用类似下面的东西来过滤正确的 ServiceLocator ......但我喜欢根据需要使用尽可能少的样板......

interface AbstractFactoryInterface
{
  public function canCreateServiceWithName(ServiceLocatorInterface $serviceLocator, $name, $requestedName);

  public function createServiceWithName(ServiceLocatorInterface $serviceLocator, $name, $requestedName);
}