## 容器和依赖注入
ThinkPHP使用容器来更方便的管理类依赖及运行依赖注入,新版的容器支持`PSR-11`规范。
> 容器类的工作由`think\Container`类完成,但大多数情况我们只需要通过`app`助手函数或者`think\App`类即可容器操作,如果在服务类中可以直接调用`this->app`进行容器操作。
依赖注入其实本质上是指对类的依赖通过构造器完成自动注入,例如在控制器架构方法和操作方法中一旦对参数进行对象类型约束则会自动触发依赖注入,由于访问控制器的参数都来自于URL请求,普通变量就是通过参数绑定自动获取,对象变量则是通过依赖注入生成。
~~~
<?php
namespace app\controller;
use think\Request;
class Index
{
protected $request;
protected $services;
public function __construct(Request $request,TestServices $services)
{
$this->request = $request;
$this->services = $services;
}
public function hello($name)
{
return 'Hello,' . $name . '!This is '. $this->request->action();
}
}
~~~
> 依赖注入的对象参数支持多个,并且和顺序无关。
支持使用依赖注入的场景包括(但不限于):
* 控制器架构方法;
* 控制器操作方法;
* 路由的闭包定义;
* 事件类的执行方法;
* 中间件的执行方法;
对于自定义的类以及方法,如果需要使用依赖注入,需要使用系统提供的`invoke`助手函数调用,例如:
~~~
class Foo
{
public function __construct(Bar $bar)
{
}
}
~~~
如果直接`new`的话,需要手动传入`Bar`对象实例
~~~
$bar = new Bar();
$foo = new Foo($bar);
~~~
如果使用容器来实例化的话,可以自动进行依赖注入。
~~~
$foo = invoke('Foo');
~~~
如果要对某个方法支持依赖注入,可以使用
~~~
class Foo
{
public function bar(Bar $bar)
{
// ...
}
}
~~~
~~~
$result = invoke(['Foo', 'bar']);
~~~
也支持对某个函数或者闭包使用依赖注入
~~~
$result = invoke(function(Bar $bar) {
// ...
});
~~~
## 绑定
依赖注入的类统一由容器进行管理,**大多数情况下是在自动绑定并且实例化的**。不过你可以随时进行手动绑定类到容器中(通常是在服务类的`register`方法中进行绑定),支持多种绑定方式。
### 绑定类标识
可以对已有的类库绑定一个标识(唯一),便于快速调用。
~~~
// 绑定类库标识
$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!');
}
}
~~~
### 批量绑定
在实际应用开发过程,不需要手动绑定,我们只需要在`app`目录下面定义`provider.php`文件(只能在全局定义,不支持应用单独定义),系统会自动批量绑定类库到容器中。
~~~
return [
'route' => \think\Route::class,
'session' => \think\Session::class,
'url' => \think\Url::class,
];
~~~
> 绑定标识调用的时候区分大小写,系统已经内置绑定了核心常用类库,无需重复绑定
系统内置绑定到容器中的类库包括
| 系统类库 | 容器绑定标识 |
| --- | --- |
| think\\App | app |
| think\\Cache | cache |
| think\\Config | config |
| think\\Cookie | cookie |
| think\\Console | console |
| think\\Db | db |
| think\\Debug | debug |
| think\\Env | env |
| think\\Event | event |
| think\\Http | http |
| think\\Lang | lang |
| think\\Log | log |
| think\\Middleware | middleware |
| think\\Request | request |
| think\\Response | response |
| think\\Filesystem | filesystem |
| think\\Route | route |
| think\\Session | session |
| think\\Validate | validate |
| think\\View | view |
## 解析
使用`app`助手函数进行容器中的类解析调用,对于已经绑定的类标识,会自动快速实例化
~~~
$cache = app('cache');
~~~
带参数实例化调用
~~~
$cache = app('cache',['file']);
~~~
对于没有绑定的类,也可以直接解析
~~~
$arrayItem = app('org\utils\ArrayItem');
~~~
> 调用和绑定的标识必须保持一致(包括大小写)
容器中已经调用过的类会自动使用单例,除非你使用下面的方式强制重新实例化。
~~~
// 每次调用都会重新实例化
$cache = app('cache', [], true);
~~~
## 对象化调用
使用`app`助手函数获取容器中的对象实例(支持依赖注入)。
~~~
$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');
~~~
然后在操作方法中自动注入User模型
~~~
<?php
namespace app\index\controller;
use app\index\model\User;
class Index
{
public function hello(User $user)
{
return 'Hello,'.$user->name;
}
}
~~~
## 自定义实例化
容器中的对象实例化支持自定义,可以在你需要依赖注入的对象中增加`__make`方法定义,例如:
如果你希望`User`模型类在依赖注入的时候 使用自定义实例化的方式,可以用下面的方法。
~~~
<?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) {
// ...
});
~~~
- 序言
- 系统简介
- 系统介绍
- 前端脑图
- 项目介绍
- 新手入门(源码安装)
- 运行环境
- 服务器配置及安装
- 视频安装教程
- 服务器及环境搭建
- 服务器购买
- 域名购买
- 域名解析
- 服务器配置
- 宝塔配置
- 创建站点
- 安装项目
- 1.源码上传(必看内容)
- 2.PHP扩展安装
- 3.环境配置
- 4.运行服务
- 5.一键安装
- 注意事项(很重要)
- 重启swoole服务
- linux安装swoole方法
- 特别注意事项
- mysql 5.7注意事项
- https域名
- ssl证书申请
- 公众号配置
- 公众号配置
- 公众号开发配置
- 公众号菜单
- 设置公众号菜单
- 关键字
- 跳转网页
- 跳转小程序
- 小程序配置
- 1.微信平台配置
- 2.CRMEB后台配置
- 3.前端提交审核
- 4.确认发布
- 支付配置
- 支付配置
- 公众号支付
- 小程序支付
- 支付宝支付
- 其他配置
- 公众号模板消息
- 小程序订阅消息
- 商业授权
- 授权说明
- 申请授权
- 安装常见问题汇总
- 请修改sql_mode文件为NO_AUTO提示
- 版本更新
- 客服设置
- uni-app 打包H5、公众号
- 版本更新
- 清空数据
- 测试域名
- 部署多套多商户
- 使用说明
- 商品分类
- 分类说明
- 分类管理
- 品牌分类
- 商品标签
- 商品管理
- 发布商品
- 商品规格
- 配置说明
- 文件上传
- 移动端展示说明
- 首页
- 分类页
- 个人中心
- 热门搜索
- 分销规则
- 分销配置
- 分销员管理
- 分销规则说明
- 分销员等级
- 分销礼包
- 佣金说明
- 用户管理
- 商户用户管理
- 平台用户管理
- 用户协议
- 用户搜索记录
- 秒杀
- 秒杀规则
- 开启秒杀活动
- 直播
- 主播实名认证
- 开启直播
- 添加直播商品
- 预售
- 开启全款预售
- 开启定金预售
- 预售协议
- 专题
- 后台配置
- 前端展示
- 助力
- 开启助力
- 查看助力活动
- 拼团
- 虚拟拼团设置
- 开启拼团
- 查看拼团活动
- 积分
- 积分设置
- 积分来源
- 积分使用
- 提现
- 提现规则
- 提现步骤
- 新闻资讯
- 新闻页面
- 发布资讯
- 账户管理
- 账号信息
- 账户资金
- 优惠券
- 添加优惠券
- 发布优惠券
- 领取及使用
- 发放优惠券
- 订单管理
- 后台订单处理
- 前端订单处理
- 订单退款
- 订单打印
- 客服管理
- 添加客服
- 客服权限
- 门店自提
- 开启门店自提
- 设置核销权限
- 订单核销说明
- 商户管理
- 商户分类
- 商户入驻
- 商户列表
- 商户菜单管理
- 店铺类型
- 财务
- 财务对账
- 发票管理
- 自动分账(v1.5及以后版本)
- 邮费说明
- 运费设置
- 运费组成
- 运费模板
- 物流配置
- 公告管理
- 店铺相关
- 店铺定位设置
- 店铺街入口
- 店铺活动
- 店铺基本信息设置
- 小票打印
- 小票打印机配置
- 小票打印机设置
- 技术文档
- 开发规范
- 数据字典
- 目录结构
- 移动端路由
- 系统配置
- 后台表单说明
- 短信设置
- 短信账户
- 短信配置
- 短信模板
- 一号通
- 电子面单
- 短信提醒
- 商品采集
- 物流查询
- 付费采集商品配置
- PC端展示说明
- PC端开启
- PC端平台页面配置
- PC端店铺页面配置
- 保障服务
- 移动端商品管理
- 开启移动端商品管理
- 功能说明
- 会员管理
- 会员管理
- 会员权益
- 会员配置
- 社区功能
- 社区分类
- 社区话题
- 社区文章
- 社区评论
- 社区配置
- 通知管理
- 移动前端
- 目录结构
- 配置说明
- 页面路径
- 后台前端说明
- 总后台目录结构
- 商户后台目录结构
- 开发和构建
- APP 打包
- 基础配置
- 开发调试
- 打包上线
- App打包
- PC端说明
- 安装教程
- 目录结构
- 打包教程
- 常见问题
- 服务器问题
- 服务器环境说明
- MySQL 5.7注意事项
- PHP fileinfo扩展安装
- 后台登录页幻灯片
- 后台登录页logo
- 论坛常见问题汇总
- 个人中心菜单加链接
- 子账号登录名
- 前后端分离配置
- 重启swoole进程
- 开论坛勋章
- 源码下载地址
- 查看/隐藏版本号
- 搜索商品后服务挂了
- 开发文档
- 架构
- config配置文件
- 容器和依赖注入
- 异常处理
- 路由
- 控制器模块
- 日志处理
- 自定义指令
- CRMEB类库
- Basic基类
- Exceptions异常处理
- Interfaces接口类
- Jobs消息队列
- services服务类
- traits
- listens定时监听类
- 接口流程
- Controller
- Repository
- Dao
- Model
- 流程
- 订单流程
- 下单流程
- 退款流程
- 二开教程
- 定义新的接口
- 创建新的页面
- 创建新的组合数据
- 更换短信模板