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

mac*_*ete 9 php frameworks service-locator zend-framework2

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

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

---+ Service
----+ LogginService.php
----+ GreetingService.php
----+ GreetingServiceFactory.php
Run Code Online (Sandbox Code Playgroud)

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

而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;
    }
}
Run Code Online (Sandbox Code Playgroud)

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

module.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'
    ),
)
Run Code Online (Sandbox Code Playgroud)

我很感激任何澄清:)

祝你今天愉快!

Ocr*_*ius 20

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

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

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;
                },
            ),
        );
    }
}
Run Code Online (Sandbox Code Playgroud)

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

ZF2为控制器,服务,视图助手,控制器插件等使用不同的服务管理器或插件管理器......主要用于类型提示(查看界面AbstractPluginManager以了解如何实现类型严格性)和安全性.

在这种情况下,安全问题是禁止访问非控制器的服务,尤其是对于具有动态controller参数的路由.这就是控制器保存在单独的插件管理器中的原因.

由于控制器插件管理器是从"主"服务管理器创建的,因此它也会被初始化ServiceLocatorAwareInterface.

为了更清楚,我添加了关系图(不包括工厂,不要将其作为有效的UML):

伪UML


Rob*_*len 5

如您所见,我需要在我的ControllerFactory中使用$ serviceLocator-> getServiceLocator(),而不是在我的ServiceFactory中.为什么?

控制器工厂由不同的服务管理器实例("ControllerLoader")调用到主工厂.这使得调度程序不能导致主服务管理器实例化任意类.

因此,当您想要检索'greetingService'时,控制器工厂的$ serviceLocator不是您需要的那个,因为'greetingService'已向主服务管理器注册.要从控制器获取主服务器管理器,请使用getServiceLocator(),然后您将拥有主服务管理器的实例,您可以从中获取()'问候服务'

这被称为'对等'.即,将"主要服务管理器"作为对等体设置"ControllerLoader"服务管理器(通过配置中的"控制器"键配置的服务管理器或模块类中的getControllerConfiguration()).