0

如果你想在中间件中有另一个中间件/对象,你必须使用像这样的工厂

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)
        );
    }
}

SoMyMiddleware将被注入,\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)
        );
    }
}

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

namespace App\Somnething;
use Zend\Expressive\Application;
class MyMiddleware
{
    /** @var Application $app */
    protected $app;

    public function __construct(Application $app)
    {
        $this->app = $app;
    }

    public function __invoke($some, $thing)
    {
        if ($some and $thing) {
            $ever = $this->app
                ->getContainer()
                ->get(\Path\To\What\Ever::class);
            $ever->doSome();
        }
    }
}
4

2 回答 2

4

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

我不建议注入容器,当然也不建议注入应用程序本身。尽管在开发过程中可能很容易,但您的应用程序变得无法测试。如果您只将所需的服务注入到中间件、操作或服务中,您可以在测试期间轻松地模拟它们。一段时间后,您会习惯在需要的地方编写工厂,并且速度很快。

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

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

<?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;
    }
}

我为此写了一篇博文

归根结底,这是您自己的决定,但最佳实践不是注入应用程序、容器或实体管理器。如果您需要调试中间件和/或为其编写测试,它将使您的生活更轻松。

于 2016-06-10T20:16:00.413 回答
0

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

1) 控制反转 (IoC)

它违反了控制反转原则,你的类不能有任何关于 IoC 容器的知识。

2)依赖倒置原则(DIP)

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

3) 得墨忒耳法则 (LoD)

根据德米特法则,单位对其他单位的了解应该是有限的,它应该只知道与其密切相关的单位。

TheMyMiddleware::class对其他单元的了解太多,首先它知道 the Application::class,然后它知道 theApplication知道 the Container,然后它知道 theContainer知道 the What\Ever::class等等。

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

于 2017-04-26T14:36:33.220 回答