文档/容器/依赖注入
依赖注入
依赖注入(也称为 Dependency injection 或 DI)是框架为创建对象的构造函数或其他方法提供依赖关系的机制。
当框架创建诸如控制器、middlewares、命令等对象时,依赖注入已在调用目标方法(包括构造函数)时设置。
根据 DI 机制,如果在方法的依赖(参数)中指定所需的类或接口,框架将尝试在容器中查找此类匹配项,从容器获取或自行创建对象并将其替换到必要的参数中。
如果在容器中未找到这样的服务,将尝试从项目中的合适类创建对象,而如果后者有自己的构造函数中的依赖,则框架将尝试以类似方式填充它们。
如果缺少具有默认值的参数的替换值,将使用默认值。
否则,框架将返回一条错误信息,指示无法成功使用指定依赖的 DI。
#框架中的 DI 实现
当框架侧创建控制器或 middleware 对象时,首先解决构造函数的依赖,然后是调用的方法。
同样,当框架处理请求时,在匹配的控制器中将只调用一个方法。在这种情况下,依赖关系的来源(来自构造函数或方法)并不重要,尽管在某些情况下,构造函数更为方便。
以下示例显示了通过 DI 从容器中不同分配 $logger 的两个控制器方法。
<?php
namespace App\Controllers;
use Hleb\Base\Controller;
use Hleb\Reference\LogInterface;
class ExampleController extends Controller
{
public function __construct(private readonly LogInterface $logger, array $config = [])
{
parent::__construct($config);
}
public function first(LogInterface $logger): void
{
}
public function second(): void
{
$logger = $this->logger;
}
}
middleware 的依赖关系以类似方式设置。
在框架命令和事件 (Events) 中,这以类似方式实现,但仅通过构造函数:
<?php
namespace App\Commands\Demo;
use Hleb\Base\Task;
use Hleb\Reference\LogInterface;
class ExampleTask extends Task
{
public function __construct(private readonly LogInterface $logger, array $config = [])
{
parent::__construct($config);
}
protected function run(): int
{
$logger = $this->logger;
return self::SUCCESS_CODE;
}
}
#使用 DI 创建对象
依赖注入的便捷之处在于,在测试期间我们可以为类的依赖关系创建必要的值。
然而,手动创建对象时,自己初始化所有依赖会不方便。
为了自动化这个过程,框架提供了 Hleb\Static\DI 类。
use Hleb\Reference\LogInterface;
use Hleb\Static\DI;
class Insert
{
}
class Example
{
public function __construct(private readonly LogInterface $logger)
{
}
public function run(Insert $insert): void
{
echo $this->logger::class;
echo ' & ';
echo $insert::class;
}
}
$exampleObject = DI::object(Example::class);
echo DI::method($exampleObject, 'run');
本节展示了如何创建一个类的对象,该类的构造函数中具有依赖项,以及如何调用对象的所需方法,该方法中也需要自动插入值。
该示例还显示了一个不是来自容器的依赖关系(Insert 类),其对象被创建并注入到方法中。
一个经常使用的 DI 变体与 Request 和 Response(在这种情况下从容器中获取):
<?php
namespace App\Controllers;
use Hleb\Base\Controller;
use Hleb\Reference\Interface\Request;
use Hleb\Reference\Interface\Response;
class MainController extends Controller
{
public function index(Request $request, Response $response): Response
{
return $response;
}
}
由于接口命名法中存在不同的方式,从容器中获取标准服务可能涉及接口以 Interface 结尾或不结尾。
例如,Hleb\Reference\RequestInterface 等同于 Hleb\Reference\Interface\Request。
← 检索服务
请求 →
页面翻译:chatgpt 4-o