Zend 表达依赖注入
Zend Expressive Dependency Injection
如果你想在中间件中有另一个 middleware/object
你必须使用像
这样的工厂
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)
);
}
}
这样就可以随时得到任何东西。
喜欢
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();
}
}
}
您不会将中间件注入其他中间件。您注入服务或存储库等依赖项。每个中间件负责一项特定的任务,如身份验证、授权、本地化协商等。它们一个接一个地执行。他们弄乱请求并将请求传递给下一个中间件。一旦中间件堆栈耗尽,响应将以相反的顺序通过所有中间件一直返回,直到它最终到达显示输出的外层。您可以在 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) 控制反转 (IoC)
违反了控制反转原则,你的class一定不了解IoC容器。
2)依赖倒置原则(DIP)
依赖倒置原则指出 "high-level modules should not depend on low-level modules",因此您的更高级别的中间件 class 依赖于 infrastructure/framework.
3) 得墨忒耳法则 (LoD)
根据得墨忒耳定律,一个单位对其他单位的了解应该是有限的,它应该只知道与其密切相关的单位。
MyMiddleware::class
对其他单位了解太多,首先它知道Application::class
,然后它知道Application
知道Container
,然后它知道 Container
知道 What\Ever::class
等等。
这种代码违反了一些最重要的 OOP 原则,导致与框架的严重耦合,它具有隐式依赖关系,至少但不是最后,难以阅读和理解。
如果你想在中间件中有另一个 middleware/object 你必须使用像
这样的工厂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)
);
}
}
这样就可以随时得到任何东西。 喜欢
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();
}
}
}
您不会将中间件注入其他中间件。您注入服务或存储库等依赖项。每个中间件负责一项特定的任务,如身份验证、授权、本地化协商等。它们一个接一个地执行。他们弄乱请求并将请求传递给下一个中间件。一旦中间件堆栈耗尽,响应将以相反的顺序通过所有中间件一直返回,直到它最终到达显示输出的外层。您可以在 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) 控制反转 (IoC)
违反了控制反转原则,你的class一定不了解IoC容器。
2)依赖倒置原则(DIP)
依赖倒置原则指出 "high-level modules should not depend on low-level modules",因此您的更高级别的中间件 class 依赖于 infrastructure/framework.
3) 得墨忒耳法则 (LoD)
根据得墨忒耳定律,一个单位对其他单位的了解应该是有限的,它应该只知道与其密切相关的单位。
MyMiddleware::class
对其他单位了解太多,首先它知道Application::class
,然后它知道Application
知道Container
,然后它知道 Container
知道 What\Ever::class
等等。
这种代码违反了一些最重要的 OOP 原则,导致与框架的严重耦合,它具有隐式依赖关系,至少但不是最后,难以阅读和理解。