容器和依赖注入
容器:就是方便把(类和对象)放入容器中,进行自动的实例化。
ThinkPHP使用容器来更方便的管理类依赖及运行依赖注入,新版的容器支持PSR-11规范
容器类的工作由think\Container类完成,但大多数情况我们只需要通过app助手函数或者think\App类即可容器操作,如果在服务类中可以直接调用this->app进行容器操作。
<?php
namespace app\controller;
use app\Model\Form;
//容器和依赖注入
class Yilaizhuru {
protected $Form;
//自动绑定
public function __construct(Form $Form){
$this->Form = $Form;
}
public function index(){
return $this->Form->userneme;
echo "index";
}
//手动绑定
public function bind(){
//绑定
bind('Form','app\model\Form');
echo "bind1";
return app('Form')->userneme;
}
//绑定传值
public function binddata(){
bind('From','app\Model\Form');
$one = app('From',[['file']],true); //Array ( ) Array ( [0] => file )
return $one->username;
}
//简单绑定
public function bindjiandan(){
return app('app\model\Form')->userneme;
}
}
<?php
namespace app\Model;
use think\Model;
class Form extends Model {
public $userneme = "这就是依赖注入";
public function __construct(array $data=[])
{
parent::__construct($data);
print_r($data);
}
}
对于自定义的类以及方法,如果需要使用依赖注入,需要使用系统提供的
invoke助手函数调用class Foo { public function __construct(Bar $bar) { } }如果直接new的话$bar = new Bar(); $foo = new Foo($bar); 如果使用容器来实例化的话,可以自动进行依赖注入。
$foo = invoke('Foo');
绑定
绑定类标识
// 绑定类库标识
$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);
绑定至接口实现
// 绑定think\LoggerInterface接口实现到think\Log
bind('think\LoggerInterface','think\Log'); 使用接口作为依赖注入的类型
<?php
namespace app\index\controller;
use think\LoggerInterface;
class Index
{
public function hello(LoggerInterface $log)
{
$log->record('hello,world!');
}
}
批量绑定
return [
'route' => \think\Route::class,
'session' => \think\Session::class,
'url' => \think\Url::class,
];
解析
$cache = app('cache'); 带参数实例化调用
$cache = app('cache',['file']); 对于没有绑定的类,也可以直接解析
$arrayItem = app('org\utils\ArrayItem'); 容器中已经调用过的类会自动使用单例,除非你使用下面的方式强制重新实例化。
// 每次调用都会重新实例化
$cache = app('cache', [], true);
对象化调用
$app = app();
// 判断对象实例是否存在
isset($app->cache);
// 注册容器对象实例
$app->cache = think\Cache::class;
// 获取容器中的对象实例
$cache = $app->cache;
也就是说,你可以在任何地方使用app()方法调用容器中的任何类,但大多数情况下面,我们更建议使用依赖注入。
// 调用配置类
app()->config->get('app_name');
// 调用session类
app()->session->get('user_name');
自动注入
Route::get('user/:id','index/Index/hello')
->model('\app\index\model\User');
<?php
namespace app\index\controller;
use app\index\model\User;
class Index
{
public function hello(User $user)
{
return 'Hello,'.$user->name;
}
}
自定义实例化
<?php
namespace app\index\model;
use think\Model;
use think\db\Query;
class User extends Model
{
public static function __make(Query $query)
{
return (new self())->setQuery($query);
}
}
容器对象回调机制
你可以通过resolving方法注册一个全局回调
Container::getInstance()->resolving(function($instance,$container) {
// ...
});
回调方法支持两个参数,第一个参数是容器对象实例,第二个参数是容器实例本身。
或者单独注册一个某个容器对象的回调
Container::getInstance()->resolving(\think\Cache::class,function($instance,$container) {
// ...
});