- 容器
用来更方便的管理类依赖及运行依赖注入的工具
- 依赖注入
依赖注入其实本质上是指对类的依赖通过构造器完成自动注入,例如在控制器架构方法和操作方法中一旦对参数进行对象类型约束则会自动触发依赖注入,由于访问控制器的参数都来自于URL请求,普通变量就是通过参数绑定自动获取,对象变量则是通过依赖注入生成
<?php
namespace app\index\controller;
use app\index\model\User;
use think\Controller;
class Index extends Controller
{
protected $user;
//通过User对象类型约束完成依赖注入
public function __construct(User $user)
{
$this->user = $user;
}
public function hello()
{
return 'Hello,' . $this->user->name . '!';
}
}
绑定
依赖注入的类统一由容器进行管理,你可以随时绑定类到容器中,支持多种绑定方式。
绑定类标识
可以对已有的类库绑定一个标识(唯一),便于快速调用。
- /thinkphp/helper.php(助手函数类)
if (!function_exists('bind')) {
/**
* 绑定一个类到容器
* @access public
* @param string $abstract 类标识、接口
* @param mixed $concrete 要绑定的类、闭包或者实例
* @return Container
*/
function bind($abstract, $concrete = null)
{
return Container::getInstance()->bind($abstract, $concrete);
}
}
if (!function_exists('app')) {
/**
* 快速获取容器中的实例 支持依赖注入
* @param string $name 类名或标识 默认获取当前应用实例
* @param array $args 参数
* @param bool $newInstance 是否每次创建新的实例
* @return object
*/
function app($name = 'think\App', $args = [], $newInstance = false)
{
return Container::get($name, $args, $newInstance);
}
}
- 调用助手函数
// 绑定类库标识
bind('cache','think\Cache')
// 快速调用(自动实例化)
$cache = app('cache')
调用和绑定的标识必须保持一致(包括大小写)
- 容器中绑定的实现
/**
* 绑定一个类、闭包、实例、接口实现到容器
* @access public
* @param string|array $abstract 类标识、接口
* @param mixed $concrete 要绑定的类、闭包或者实例
* @return $this
*/
public function bind($abstract, $concrete = null)
{
if (is_array($abstract)) {
$this->bind = array_merge($this->bind, $abstract);
//Closure 是匿名函数的类,匿名函数(在 PHP 5.3 中被引入)会产生这个类型的对象。
} elseif ($concrete instanceof Closure) {
$this->bind[$abstract] = $concrete;
} elseif (is_object($concrete)) {
$this->instances[$abstract] = $concrete;
} else {
$this->bind[$abstract] = $concrete;
}
return $this;
}
绑定闭包
bind('sayHello', function ($name) {
return 'hello,' . $name;
});
echo app('sayHello',['thinkphp']);
绑定类的实例
$cache = new think\Cache;
// 绑定类实例
bind('cache',$cache);
// 快速调用类的实例
$cache = app('cache');
绑定至接口实现
对于依赖注入使用接口类的情况,我们需要告诉系统使用哪个具体的接口实现类来进行注入,这个使用可以把某个类绑定到接口
// 绑定think\LoggerInterface接口实现到think\Lobind('think\LoggerInterface','think\Log'
使用接口作为依赖注入的类型
<?php
namespace app\index\controller;
use think\LoggerInterface;
class Index
{
public function hello(LoggerInterface $log)
{
$log->record('hello,world!');
}
}
批量绑定
如果传入一个数组的话,就表示进行批量绑定
//关键词 class 也可用于类名的解析。使用 ClassName::class 你可以获取一个字符串,包含了类 ClassName 的完全限定名称。这对使用了命名空间的类尤其有用。
bind(['route' => \think\Route::class,
'session' => \think\Session::class,
'url' => \think\Url::class]);
可以在应用或者模块目录下面定义 provider.php 文件(返回一个数组),系统会自动批量绑定类库到容器中。
return [
'route' => \think\Route::class,
'session' => \think\Session::class,
'url' => \think\Url::class
];
系统内置绑定到容器中的类库
// 注册核心类到容器
Container::getInstance()->bind([
'app' => App::class,
'build' => Build::class,
'cache' => Cache::class,
'config' => Config::class,
'cookie' => Cookie::class,
'debug' => Debug::class,
'env' => Env::class,
'hook' => Hook::class,
'lang' => Lang::class,
'log' => Log::class,
'request' => Request::class,
'response' => Response::class,
'route' => Route::class,
'session' => Session::class,
'url' => Url::class,
'validate' => Validate::class,
'view' => View::class,
'middlewareDispatcher' => http\middleware\Dispatcher::class,
// 接口依赖注入
'think\LoggerInterface' => Log::class,
]);