## 容器和依賴注入
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
- 流程
- 訂單流程
- 下單流程
- 退款流程
- 二開教程
- 定義新的接口
- 創建新的頁面
- 創建新的組合數據
- 更換短信模板