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