Zend表达依赖注入

时间:2016-06-10 13:32:54

标签: zend-framework dependency-injection factory zend-expressive

如果您想在中间件中使用另一个中间件/对象 你必须使用像

这样的工厂
recv()

因此namespace App\Somnething; use Interop\Container\ContainerInterface; class MyMiddlewareFactory { public function __invoke(ContainerInterface $container, $requestedName) { return new $requestedName( $container->get(\App\Path\To\My\Middleware::class) ); } } 会注入MyMiddleware,我们就可以访问它了。

问题: 用应用程序本身或容器注入中间件是不对的?像:

\App\Path\To\My\Middleware

这样就可以随时获得任何东西。 像

namespace App\Somnething;
use Interop\Container\ContainerInterface;
use Zend\Expressive\Application;
class MyMiddlewareFactory
{
    public function __invoke(ContainerInterface $container, $requestedName)
    {
        return new $requestedName(
            $container->get(Application::class)
        );
    }
}

2 个答案:

答案 0 :(得分:4)

您不会将中间件注入其他中间件。您注入了服务或存储库之类的依赖项。每个中间件都负责一个特定的任务,如身份验证,授权,本地化协商等。它们一个接一个地执行。他们乱用请求并将请求传递给下一个中间件。一旦中间件堆栈耗尽,响应将以相反的顺序一直返回所有中间件,直到它最终到达显示输出的外层。您可以在expressive docs中找到流程概述。

我不建议注入容器,当然不是应用程序本身。虽然在开发过程中可能很容易,但您的应用程序变得不可测试。如果只将中间件,操作或服务所需的服务注入,则可以在测试期间轻松模拟这些服务。过了一段时间,你习惯于在需要的地方写工厂,而且速度非常快。

注入实体管理器(如果使用原则)也是如此。如果您只注入所需的存储库,那么测试应用程序会更容易,您可以轻松地模拟它。

话虽如此,如果您正在寻找一种注入依赖关系的简单方法,那么zend-servicemanager可以做到这一点。看看abstract factories。使用抽象工厂,您可以为所有操作类创建一个工厂:

<?php

namespace App\Action;

use Interop\Container\ContainerInterface;
use ReflectionClass;
use Zend\ServiceManager\Factory\AbstractFactoryInterface;

class AbstractActionFactory implements AbstractFactoryInterface
{
    public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
    {
        // Construct a new ReflectionClass object for the requested action
        $reflection = new ReflectionClass($requestedName);
        // Get the constructor
        $constructor = $reflection->getConstructor();
        if (is_null($constructor)) {
            // There is no constructor, just return a new class
            return new $requestedName;
        }

        // Get the parameters
        $parameters = $constructor->getParameters();
        $dependencies = [];
        foreach ($parameters as $parameter) {
            // Get the parameter class
            $class = $parameter->getClass();
            // Get the class from the container
            $dependencies[] = $container->get($class->getName());
        }

        // Return the requested class and inject its dependencies
        return $reflection->newInstanceArgs($dependencies);
    }

    public function canCreate(ContainerInterface $container, $requestedName)
    {
        // Only accept Action classes
        if (substr($requestedName, -6) == 'Action') {
            return true;
        }

        return false;
    }
}

我写了blog post

在一天结束时,这是您自己的决定,但最佳做法不是注入应用,容器或实体经理。如果您需要调试中间件和/或为其编写测试,它将使您的生活更轻松。

答案 1 :(得分:0)

可以在中间件中注入应用程序或容器,但这根本不是一个好主意:

1)控制反转(IoC)

它违反了控制原则的反转,你的班级不得对IoC容器有任何了解。

2)依赖性倒置原则(DIP)

依赖性倒置原则指出“高级模块不应该依赖于低级模块”,因此更高级别的中间件类依赖于基础架构/框架。

3)得墨忒耳定律(LoD)

根据德米特定律,该单位对其他单位的了解应该有限,只应了解其密切相关的单位。

MyMiddleware::class对其他单位有太多了解,首先,它知道Application::class,然后知道Application知道Container,然后它知道Container知道What\Ever::class等等。

这种代码违反了一些最重要的OOP原则,导致与框架的可怕耦合,它具有隐含的依赖性,而且最少但不是最后,很难被阅读和理解。