如果您想在中间件中使用另一个中间件/对象 你必须使用像
这样的工厂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)
);
}
}
答案 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原则,导致与框架的可怕耦合,它具有隐含的依赖性,而且最少但不是最后,很难被阅读和理解。