php - 为什么要使用 Zend Framework 2 中的服务管理器?

标签 php service zend-framework2 factory-pattern service-management

假设我有一项服务:

namespace Helloworld\Service;

class GreetingService
{
    public function getGreeting()
    {
        if(date("H") <= 11)
            return "Good morning, world!";
        else if (date("H") > 11 && date("H") < 17)
            return "Hello, world!";
        else
            return "Good evening, world!";
    }
}

我为它创建了一个可调用对象

public function getServiceConfig()
{
    return array(
        'invokables' => array(
            'greetingService'
                => 'Helloworld\Service\GreetingService'
        )
    );
}

然后在我的 Controller 中我可以做:

public function indexAction()
{
    $greetingSrv = $this->getServiceLocator()
        ->get('greetingService');

    return new ViewModel(
        array('greeting' => $greetingSrv->getGreeting())
    );
}

据说这使得 Controller 依赖于服务(和 ServiceManager)

更好的解决方案是为该服务创建工厂或在 ServiceManager 中返回一个闭包并在 Controller 中创建一个 setter:

class IndexController extends AbstractActionController
{
    private $greetingService;

    public function indexAction()
    {

        return new ViewModel(
            array(
                'greeting' => $this->greetingService->getGreeting()
            )
        );
    }

    public function setGreetingService($service)
    {
        $this->greetingService = $service;
    }
}

'controllers' => array(
    'factories' => array(
        'Helloworld\Controller\Index' => function($serviceLocator) {
            $ctr = new Helloworld\Controller\IndexController();

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

            return $ctr;
        }
    )
)

我的问题是为什么?为什么第二种方法比第一种更好? Controller 依赖于服务是什么意思

谢谢

最佳答案

ServiceManager 默认情况下注入(inject)到任何 ZF2 Controller 中,因为它扩展了实现 ServiceLocatorAwareInterface 接口(interface)的 AbstractController

第二种方法的形式是“redundancy”,因为除了已经可以访问 ServiceManager 实例之外,只要您需要在 Controller 之间共享服务,就需要为每个 Controller 配置其中之一是注入(inject)机制。由于您的 Controller 已经对 ServiceManager 具有依赖性,因此使用第一种方法并将您的域相关服务注册到 ServiceManager 会更有意义,从而集中对服务层的访问.

Note: The following part of the answer may go beyond the scope of the question, but it aims to provide the "hidden" background of the original one.

假设我们正在构建一个复杂的系统,在该系统中提升了低耦合性、可重用性和可测试性。我们的系统是多层的,我们构建了一切,直到服务层。请注意,直到现在我们还没有考虑“MVC”网络层,甚至没有选择给定的框架。

在我们的服务层(我会考虑这一层,因为它是问题中提到的那一层),我们假设我们采用了 principle业务逻辑和对象图构造(或依赖关系解析)之间的分离。因此,我们可能有几个通过工厂构建的复杂服务。

现在我们的服务层已经构建完成,我们决定将其“插入”到 ZF2 之上。当然,我们的服务应该可以从 Controller 访问,正如您的问题所说明的那样,我们有不止一种方法可以做到这一点。但是,我们希望避免冗余并利用我们已经构建的内容。让我们假设以下工厂:

//The following class is a part of our Service layer
public class ComplexServiceFactory{

    private dependencyA;
    private dependencyB;

    public function buildComplexService()
    {
        $service = new ComplexService();
        $service->setDependencyA($this->dependecyA);
        $service->setDependencyB($this->dependecyB);
        return $service;
    }

}

我们现在要做的只是调整(实际上是扩展)我们的工厂,以便它可以被 ServiceManager 逻辑使用。此类可以被视为用于将我们的系统“插入”到 ZF2 的机制的一部分(它实际上是一个 Adapter )

public class SMComplexServiceFactory extends ComplexServiceFactory implements
    Zend\ServiceManager\FactoryInterface
{

    public function createService(ServiceLocatorInterface $sm)
    {
        $this->setDependencyA($sm->get('dependecyA'));
        $this->setDependencyB($sm->get('dependecyB'));
        return parent::buildComplexService;
    }

}

通过这样做,我们不会将对象图构造引入 MVC 层(否则会违反 Separation of Concerns 和不必要的跨层耦合)。服务管理器 + 我们的“适配”工厂类在某种意义上是我们的依赖性解决机制。事实上我们的系统仍然是可移植的,例如我们可以选择另一个系统(另一个框架)并且对 MVC 平台的依赖性较低。

关于php - 为什么要使用 Zend Framework 2 中的服务管理器?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14550978/

相关文章:

javascript - ZF2 headScript 包含两次相同的文件

php - 从 MySQL 数据库中获取 Google Maps .getBounds 中的所有记录?

php - fgets() 和 fread() - 有什么区别?

php - 包含标签的全文搜索

android - Activity 管理器崩溃

zend-framework2 - ZF2 获取 POST 和 GET 的值

php - 如何将我的 zend framework 2 应用程序部署到 AWS elastic beanstalk?

PhpStorm - 参数的 PHPDoc "any"类型

android - 服务停止时所有线程都会被杀死吗?

java - 如何找到我的 Web 服务的 URL?