[TOC]
## **依賴注入**
依賴注入其實本
質上是指對類的依賴通過構造器完成自動注入,例如在控制器架構方法和操作方法中一旦對參數進行對象類型約束則會自動觸發依賴注入:
~~~
namespace app\controller;
use think\Request;
class Index
{
protected $request;
//由于訪問控制器的參數都來自于URL請求
//普通變量就是通過參數綁定自動獲取
public function __construct(Request $request)
{
$this->request = $request;
}
//對象變量則是通過依賴注入生成。
public function hello($name)
{
return 'Hello,' . $name . '!This is '. $this->request->action();
}
}
~~~
>[danger]容器類的工作由`think\Container`類完成,但大多數情況我們只需要通過`app`助手函數或者`think\App`類即可容器操作(App是繼承與Container的),如果在服務類中可以直接調用`this->app`進行容器操作。
依賴注入的對象參數支持多個,并且和順序無關。
通常一個類使用其他類時需要手動傳入,如在類Foo中使用類Bar:
~~~
class Foo
{
private $bar;
public function __construct(Bar $bar)
{
$this->bar=$bar;
}
public function bar(Bar $bar)
{
// ...
}
}
class Bar{}
$bar = new Bar();
$foo = new Foo($bar);
~~~
**在thinkphp可以使用容器相關的助手函數invoke對它的某個方法實現依賴注入,這樣只要在架構函數(__construct)或者方法中申明為參數則會自動注入**
1、如果使用容器來實例化的話,可以自動進行依賴注入到__construct。
~~~
$foo = invoke('Foo');
~~~
2、如果要對某個方法支持依賴注入,如Foo的bar方法 可以使用
```
$result = invoke(['Foo', 'bar']);
```
3、也支持對某個函數或者閉包使用依賴注入
~~~
$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`助手函數進行容器中的類解析調用,對于已經綁定的類標識,會自動快速實例化
app封裝了容器的make方法它的作用是:創建類的實例 已經存在則直接獲取 返回的是指定類實例
~~~
$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) {
// ...
});
~~~
- 空白目錄
- php語法結構
- 安裝與更新
- 開啟調試模式及代碼跟蹤器
- 架構
- 源碼分析
- 應用初始化
- 請求流程
- 中間件源碼分析
- 請求處理源碼分析
- Request源碼分析
- 模板編譯流程
- 路由與請求流程
- 容器
- 獲取目錄位置
- 入口文件
- 多應用模式及URL訪問
- 依賴注入與容器
- 容器屬性及方法
- Container
- App
- facade
- 中間件(middleware)
- 系統服務
- extend 擴展類庫
- 筆記
- 配置
- env配置定義及獲取
- 配置文件的配置獲取
- 單應用模式-(配置)文件目錄結構(默認)
- 多應用模式(配置)文件目錄結構(配置文件)
- 配置文件
- 應用配置:app.php
- 緩存配置: cache.php
- 數據庫配置:database.php
- 路由和URL配置:route.php
- Cookie配置:cookie.php
- Session配置:session.php
- 命令行配置:console.php
- 多語言配置:lang.php
- 日志配置:log.php
- 頁面Trace配置:trace.php
- 磁盤配置: filesystem.php
- 中間件配置:middleware.php
- 視圖配置:view.php
- 改成用yaconf配置
- 事件
- 例子:省略事件類的demo
- 例子2:完整事件類
- 例子3:事件訂閱,監聽多個事件
- 解析
- 路由
- 路由定義
- 路由地址
- 變量規則
- MISS路由
- URL生成
- 閉包支持
- 路由參數
- 路由中間件
- 路由分組
- 資源路由
- 注解路由
- 路由綁定
- 域名路由
- 路由緩存
- 跨域路由
- 控制器
- 控制器定義
- 空控制器、空操作
- 空模塊處理
- RESTFul資源控制器
- 控制器中間件
- 請求對象Request(url參數)
- 請求信息
- 獲取輸入變量($_POST、$_GET等)
- 請求類型的獲取與偽裝
- HTTP頭信息
- 偽靜態
- 參數綁定
- 請求緩存
- 響應對象Response
- 響應輸出
- 響應參數
- 重定向
- 文件下載
- 錯誤頁面的處理辦法
- 應用公共文件common.php
- 模型
- 模型定義及常規屬性
- 模型數據獲取與模型賦值
- 查詢
- 數據集
- 增加
- 修改
- 刪除
- 條件
- 查詢范圍scope
- 獲取器
- 修改器
- 搜索器
- 軟刪除
- 模型事件
- 關聯預載入
- 模型關聯
- 一對一關聯
- 一對多關聯
- 多對多關聯
- 自動時間戳
- 事務
- 數據庫
- 查詢構造器
- 查詢合集
- 子查詢
- 聚合查詢
- 時間查詢
- 視圖查詢(比join簡單)
- 獲取查詢參數
- 快捷方法
- 動態查詢
- 條件查詢
- 打印sql語句
- 增
- 刪
- 改
- 查
- 鏈式操作
- 查詢表達式
- 分頁查詢
- 原生查詢
- JSON字段
- 鏈接數據庫配置
- 分布式數據庫
- 查詢事件
- Db獲取器
- 事務操作
- 存儲過程
- Db數據集
- 數據庫驅動
- 視圖
- 模板
- 模板配置
- 模板位置
- 模板渲染
- 模板變量與賦值(assign)
- 模板輸出替換
- url生成
- 模板詳解
- 內置標簽
- 三元運算
- 變量輸出
- 函數輸出
- Request請求參數
- 模板注釋及原樣輸出
- 模板繼承
- 模板布局
- 原生PHP
- 模板引擎
- 視圖過濾
- 視圖驅動
- 驗證
- 驗證進階之最終版
- 錯誤和日志
- 異常處理
- 日志處理
- 調試
- 調試模式
- Trace調試
- SQL調試
- 變量調試
- 遠程調試
- 雜項
- 緩存
- Session
- Cookie
- 多語言
- 上傳
- 擴展說明
- N+1查詢
- TP類庫
- 擴展類庫
- 數據庫遷移工具
- Workerman
- think助手工具庫
- 驗證碼
- Swoole
- request
- app
- Response
- View
- Validate
- Config
- 命令行
- 助手函數
- 升級指導(功能的添加與刪除說明)
- siyucms
- 開始
- 添加頁面流程
- 列表頁加載流程
- 彈出框
- 基礎控制器
- 基礎模型
- 快速構建
- 表單form構建
- 表格table構建
- MakeBuilder
- 前端組件
- 日期組件
- layer 彈層組件
- Moment.js 日期處理插件
- siyucms模板布局
- 函數即其變量
- 前端頁面
- $.operate.方法
- $.modal.方法:彈出層
- $.common.方法:通用方法
- 被cms重寫的表格options
- 自定義模板
- 搜索框
- 自定義form表單
- 獲取表單搜索參數并組裝為url字符串