容器和依赖注入
容器:就是方便把(类和对象)放入容器中,进行自动的实例化。
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) {
// ...
});