一、簡介
你可以把行爲理解成是“在程序執行過程中的某一個位置會調起一個或一類事件”的動作。行爲發生作用的位置我們稱之爲鉤子,當應用程序運行到這個鉤子的時候,就會被攔截下來,統一執行相關的行爲。
類似於AOP
編程中的“切面”的概念,給某一個鉤子綁定相關行爲就成了一種類AOP
編程的思想。
一個完整的行爲事件包括以下三項:
1)行爲定義
2)行爲綁定
3)監聽鉤子
ThinkPHP關於行爲的核心方法都定義於核心文件thinkphp\library\think\Hook.php
中。
二、行爲定義
行爲類一般放置於模塊目錄下的behavior目錄裏,當然這不是硬性要求,你也可以按照你的喜好自定義目錄。
行爲類的定義很簡單,一般來說只需要定義一個行爲入口方法run即可。如,我需要給我的後臺管理系統做一個用戶登錄行爲檢測:
namespace app\admin\behavior;
/**
* Test: Use to learn ThinkPHP-Hook.
*
* Email: [email protected]
* Author: Chan
*/
class MyHook
{
public function run($params){
echo '<b>自定義鉤子的行爲</b>';
}
}
行爲的入口方法名稱支持自定義,如果需要更改在應用公共文件(common.php)中添加下面的代碼即可:
Hook::portal('portal');
一個鉤子可以註冊多個行爲,執行到某個鉤子位置後,會按照註冊的順序依次執行相關的行爲。但在某些特殊的情況下,你可以設置某個鉤子只能執行一次行爲,又或者你可以在一個鉤子的某個行爲中返回false來強制終止後續的行爲執行;一個行爲可以同時註冊到多個不同的鉤子上,完全看應用的需求來設計。
可以在行爲方法中使用依賴注入,例如:
namespace app\index\behavior;
use think\Request;
class Test
{
public function run(Request $request, $params)
{
// 行爲邏輯
}
}
三、行爲綁定
行爲定義完成後,就需要綁定到某個標籤位置(鉤子)才能生效,否則是不會執行的。
1、通過配置文件
我們可以直接在應用目錄下面或者模塊的目錄下面定義tags.php文件來統一定義行爲,定義格式如下:
// 應用行爲擴展定義文件
return [
// 模塊初始化
'module_init' => ['app\\admin\\behavior\\Login'],
// 操作開始執行
'action_begin' => [],
// 視圖內容過濾
'view_filter' => [],
// 日誌寫入
'log_write' => [],
// 應用結束
'app_end' => [],
//自定義鉤子 => 綁定相應的行爲
'my_hook' => ['app\\admin\\behavior\\MyHook'],
];
2、使用think\facade\Hook類的add方法註冊行爲
Hook::add('my_hook','app\\admin\\behavior\\MyHook');
注意:
1)Hook::add要執行在Hook::listen之前,否則不會綁定成功。
2)Hook::add要麼調用run方法要麼調用當前鉤子名稱(駝峯法)的方法。
如果需要使用Hook::add調用其它方法,可以定義靜態方法(app\index\behavior\CheckAuth::hello)
或者使用閉包。
四、監聽鉤子
鉤子的位置必須是事先設計好的,無論是框架還是應用的,要設置一個鉤子,只需要在相關的位置添加一行代碼(事先需要引入think\facade\Hook類),語法如下:
Hook::listen('鉤子名稱','參數','是否只有一次有效返回值');
1、系統鉤子
系統鉤子就是框架已經默認設置好的,開發者可以直接使用。
鉤子 | 描述 | 參數 |
---|---|---|
app_init | 應用初始化標籤位 | 無 |
app_dispatch | 應用調度標籤位 | 無 |
app_begin | 應用開始標籤位 | 無 |
module_init | 模塊初始化標籤位 | 無 |
action_begin | 控制器開始標籤位 | 當前的callback參數 |
view_filter | 視圖輸出過濾標籤位 | 當前模板渲染輸出內容 |
app_end | 應用結束標籤位 | 當前響應對象實例 |
log_write | 日誌write方法標籤位 | 當前寫入的日誌信息 |
log_level | 日誌寫入標籤位 | 包含日誌類型和日誌信息的數組(V5.1.25+) |
response_send | 響應發送標籤位 | 當前響應對象 |
response_end | 輸出結束標籤位 | 當前響應對象實例 |
2、自定義鉤子
use think\facade\Hook;
Hook::listen('module_init'); //監聽系統鉤子 module_init
Hook::listen('my_hook'); //監聽自定位鉤子 my_hook
五、閉包支持
可以不用定義行爲直接把閉包函數綁定到某個標籤位,例如:
Hook::add('hook_function',function($params){
var_dump($params);
});
Hook::listen('hook_function','Hi nosee!');
六、直接執行行爲
如果需要,你也可以不綁定行爲標籤,直接調用某個行爲,使用:
// 執行 app\index\behavior\CheckAuth行爲類的run方法 並引用傳入params參數
$result = Hook::exec('app\\index\\behavior\\CheckAuth',$params);
直接執行行爲的時候,執行的是run方法,如果需要執行行爲類的其它方法,可以使用
// 執行 app\index\behavior\CheckAuth行爲類的hello方法 並引用傳入params參數
$result = Hook::exec(['app\\index\\behavior\\CheckAuth','hello'], $params);