导语

容器和依赖注入大部分人官方文档难以消化,一方面两个概念不好理解,过于术语化,二是文档范例没有更接地气的范例。

依赖注入

  • 依赖注入其实本质上是指对类的依赖通过构造器完成自动注入;
  • 在控制器架构方法和操作和方法中一旦对参数进行对象类型约束则会自动触发依赖注入,由于访问控制器的参数都来自于 URL 请求,普通变量就是通过参数绑定自动获取,对象变量则是通过依赖注入生成。
  • 依赖注入:即允许通过类的方法传递对象的能力,并且限制了对象的类型(约束);
  • 传递的对象背后的那个类被自动绑定并且实例化了,这就是依赖注入;

容器

ThinkPHP引入的容器,到底是什么意思?

官方是这么说的:ThinkPHP使用容器来更方便的管理类依赖及运行依赖注入。容器和依赖注入 · ThinkPHP6.0完全开发手册 · 看云

通俗点说就是:tp6实现了个容器类,这个类专门处理依赖注入的实例对象,比如框架内置绑定到容器中的类有:

内置类库容器绑定标识
think\Cachecache
think\Configconfig
think\Cookiecookie
think\Requestrequest
think\Responseresponse
think\Filesystemfilesystem
think\Routeroute
think\Sessionsession
--

当然我们也可以将自定义类注入到容器中,供业务逻辑类使用,举个例子:

class A(){

    private $b;
    public function __construct(Request $request, B $b){
        $this->b = $b;
    }
}

class B(){
    //...
}

//没有使用依赖注入之前,我们需要手动实例化B对象,并传参给类A,进行实例化:
$a = new A(new think\Request(), new B());
//如果使用tp6的依赖注入,通过助手函数invoke:
$a = invoke('A');//框架会通过依赖注入,将实例化B,并注册到框架容器中,省去了手动实例化,及可以在容器类中统一管理这些注入对象

依赖注入的类统一由容器进行管理,大多数情况下是在自动绑定并且实例化的。

绑定与解析类库

除了调用时自动注入容器外,我们还可以手动绑定类库到容器中。

可以对已有的类库绑定一个标识(唯一),便于快速调用。

// 绑定类库标识
$this->app->bind('think\Cache', 'app\common\Cache');

// 或者使用助手函数 绑定类库标识
bind('cache', 'think\Cache');

//绑定一个闭包
bind('sayHello', function ($name) {
    return 'hello,' . $name;
});

// 绑定类实例
$cache = new think\Cache;
bind('cache', $cache);

//使用助手函数app解析使用容器中的类或对象或函数等
$cache = app('cache');

批量绑定

在实际应用开发过程,不需要手动绑定,我们只需要在app目录下面定义provider.php文件(只能在全局定义,不支持应用单独定义),系统会自动批量绑定类库到容器中。

return [
    'route'      => \think\Route::class,
    'session'    => \think\Session::class,
    'url'        => \think\Url::class,
];

注意:绑定标识主要是为了方便记住与快速使用,我们也可以解析一个未绑定的类,只是没有简短的标识,需要类完整命名空间路径:

$arrayItem = app('org\utils\ArrayItem');

依赖注入的常见场景

支持使用依赖注入的场景包括(但不限于)可能有问题:

  • 控制器架构方法;
  • 控制器操作方法;
  • 路由的闭包定义;
  • 事件类的执行方法;
  • 中间件的执行方法;