Laravel 依赖注入的实现
依赖注入
网上已经有许多不错的文章介绍依赖注入了,维基百科-DI也有其详细的介绍。
翻译一段PHP-DI官网的解释:
在没有使用依赖注入的框架代码中:
- App需要Foo
- App创建了Foo
- App调用了Foo
- Foo需要Bar
- Foo创建Bar
- Foo调用Bar
- Bar需要Bim
- Bar创建Bim
- Bar调用Bim
- Bim做某些事情
- Bar做某些事情
- Foo做某些事情
在实现了依赖注入的框架代码中:
- App需要Foo,Foo需要Bar,Bar需要Bim
- App创建Bim
- App创建Bar,并提供Bim
- App创建Foo,并提供Bar
- App调用Foo
- Foo调用Bar
- Bar调用Bim
- Bim做某些事情
- Bar做某些事情
- Bar调用Bim
- Foo做某些事情
- Foo调用Bar
App在这里就相当于一个IOC(Inversion of Control控制反转)容器,依赖注入是IOC最普遍的一种实现。App负责创建实例,调用方只需要告诉App需要哪个类的实例就可以了。
Laravel的容器
Laravel的App是Illuminate\Foundation\Application
,该类继承了Illuminate\Container\Container
(容器核心功能的实现)。
那么Laravel是怎么来使用这个App容器的呢?
首先,需要向容器声明一些依赖关系,如源码boostrap\app.php
中:
<?php
$app->singleton(
Illuminate\Contracts\Http\Kernel::class,
App\Http\Kernel::class
);
这段代码意思是向App容器声明,当我需要一个Illuminate\Contracts\Http\Kernel
的实例时,创建一个单实例的App\Http\Kernel
给我。
在源码public/index.php
中:
<?php
$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);
这段代码的意思是向App容器请求一个Illuminate\Contracts\Http\Kernel
的实例。
关于Laravel容器的使用可查看其官方文档:Service Container。
Laravel的参数注入
参数注入是依赖注入的方式之一,在Laravel中,我们最经常使用到的就是参数注入,比如我们可以在某个控制器的某个方法中声明我们需要一个UserRepository类的对象作为参数传入:
<?php
/**
* Get user info.
*
* @param UserRepository $users
* @return void
*/
public function info(UserRepository $users)
{
$this->users = $users;
}
这个UserRepository对象并不需要我们手动传入,框架在调用控制器的info方法的时候,会自动从容器中获取一个UserRepository的对象作为info方法的参数。
框架又是如何知道info方法需要一个UserRepository对象呢?
答案就是反射。Laravel通过PHP反射的特性:ReflectionMethod,来获取info方法依赖的参数信息。