文档/容器/依赖注入

依赖注入

依赖注入(也称为 Dependency injectionDI)是框架为创建对象的构造函数或其他方法提供依赖关系的机制。

当框架创建诸如控制器、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
    
{
        
// variant 1
    
}

    public function 
second(): void
    
{
        
// variant 2
        
$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;

// Demo class for insertion.
class Insert
{
}

// Class with dependencies.
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'); // Hleb\Reference\LogReference & Insert

本节展示了如何创建一个类的对象,该类的构造函数中具有依赖项,以及如何调用对象的所需方法,该方法中也需要自动插入值。 该示例还显示了一个不是来自容器的依赖关系(Insert 类),其对象被创建并注入到方法中。

一个经常使用的 DI 变体与 RequestResponse(在这种情况下从容器中获取):

<?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 $requestResponse $response): Response
    
{
        
// ... //

        
return $response;
    }
}

由于接口命名法中存在不同的方式,从容器中获取标准服务可能涉及接口以 Interface 结尾或不结尾。 例如,Hleb\Reference\RequestInterface 等同于 Hleb\Reference\Interface\Request

检索服务 请求

页面翻译:chatgpt 4-o
返回顶部