[thinkphp3.2]行爲擴展以及插件機制介紹!

看了一下,3.2出來還沒多久,貌似沒有關於3.2的行爲擴展和插件機制的教程帖子,手冊裏也是渺渺幾筆,等於沒說,這篇文章向大家介紹一下3.2的行爲擴展和插件機制。

首先行爲擴展這個概念是TP架構的核心組成之一,關於行爲的解釋我就粗略的概括一下吧:
TP在從接受到HTTP請求到最終將視圖輸出,期間經歷的很多步驟,這些步驟大家可以在http://document.thinkphp.cn/manual_3_2.html#system_process 這裏面看到,這裏就不再詳細敘述了,那麼行爲擴展實際上就是在這些流程裏埋下了一個鉤子,你可以往鉤子裏添加你自己的業務邏輯,當程序執行到某個鉤子位置時將自動觸發你的業務邏輯,關於系統預置的一些鉤子可以參考:
http://document.thinkphp.cn/manual_3_2.html#behavior_extend

本文的主要目的是教大家如何使用行爲擴展和插件,這裏爲什麼要提到"插件"這個詞呢?因爲在3.2裏,有了一個插件的概念,和行爲共用一個Hook類,所以放在一起說,原理上並無太大區別。

一、行爲擴展篇
1.TP內置行爲鉤子
我們知道TP中預留了一些行爲鉤子,比如 action_begin,這個鉤子是在動作開始執行時觸發,預置的鉤子大家通過配置文件註冊行爲類,大家在Application/Common/Conf目錄下創建一個tags.php,這個和3.1是一樣的,返回一個數組,數組格式是 "鉤子名"=>array("行爲類1","行爲類2"......)
這裏我給一個例子:
Application/Common/Conf/tag.php:
<?php
return array(
"action_begin" => array("Behaviors\\test")
);
?>
可以看到,我往action_begin這個鉤子裏面註冊了一個行爲,這個行爲就是Behaviors\\test 這裏的寫法是命名空間寫法,其對應的類文件路徑是:
Application/Behaviors/testBehavior.class.php
注意實際類文件名需要加上Behavior後綴,以及用.class.php作爲文件擴展名。
Application/Behaviors/testBehavior.class.php:
<?php
namespace Behaviors;
class testBehavior{
function run($arg){
echo "這是一個行爲擴展".$arg;
}
}
?>
千萬要注意第一行的命名空間,對於命名空間不理解的請自行查閱php手冊。另外對於TP的自動加載機制,參考手冊:
http://document.thinkphp.cn/manual_3_2.html#autoload
行爲的執行入口是 run()方法,觸發鉤子時會自動執行行爲類裏的run()方法。

2.動態添加鉤子和註冊行爲
通過上面的例子大家纔是瞭解了行爲大概是個什麼東西,但是對於其執行流程可能還不清楚,這裏我來介紹下動態添加鉤子和註冊行爲,使大家對行爲執行機制有一個比較清晰的理解。
首先,行爲鉤子添加和註冊行爲類,以及觸發行爲,都是通過Hook類來實現的,Hook類在TP核心包裏的ThinkPHP目錄下,Hook.class.php.
>>添加鉤子以及註冊行爲:\Think\Hook::add('鉤子名','行爲')
>>埋設/監聽/觸發鉤子:\Think\Hook::listen('鉤子名','傳遞給run的參數,必須是個變量');
假設我們需要在訪問index.php/Public/login.html的時候觸發login鉤子裏的行爲,那麼首先我們需要在login方法中監聽鉤子,也就是把鉤子埋在login方法裏,當訪問login方法時就會自動觸發,有點像獵人的陷阱不是嗎?
function login(){
\Think\Hook::listen('login');//監聽一個名爲login的鉤子
...其他代碼略...
}
好了,我們在login方法裏監聽了login鉤子,那麼接下來我們往這個鉤子裏添加一些行爲,這樣訪問login的時候會自動觸發這些行爲,執行行爲類的run方法。
行爲在哪裏註冊呢?
當然得在觸發之前註冊,1.你可以通過tags.php註冊,上面提到過了,只不過把action_begin換成login。2.動態添加,假如你這個鉤子只在Public控制器中使用,那麼你可以在PublicController的_initialize()初始化方法中動態添加鉤子。
function _initialize(){
\Think\Hook::add('login','Behaviors\\test');
}
這裏就往login這個鉤子裏添加了一個test行爲,比較懶直接從上面複製過來了,大家理解這個意思就可以。
添加多個行爲的話可以這樣
\Think\Hook::add('login',array('Behaviors\\test','Behaviors\\test1'...));
就是第二個參數變成一個數組,數組裏每個元素對應一個行爲類,注意,當鉤子被觸發時,這裏面的所有行爲都會依次執行。

3.帶參數的行爲
上面我們知道了行爲是通過run()方法執行的,那麼我們想傳遞一些參數進去怎麼辦呢?
答案是 \Think\Hook::listen(); 的第二個參數。
注意listen方法定義如下:
static public function listen($tag, &$params=NULL)
可以看到第二個參數是一個引用傳遞的參數,也就是說,第二個參數必須是一個變量,不能是值,下面的使用方法是錯誤的:
\Think\Hook::listen('login',"hello"); // x
這樣纔是正確的
$hello = "hello";
\Think\Hook::listen('login',$hello);//√
關於引用傳遞的知識這裏不作介紹,請自行翻閱PHP手冊。

這樣我們在行爲類裏面run方法可以指定一個參數來接收$hello
function run($arg){
echo $arg;//輸出 hello
}
當然你也可以
function run(&$arg){
echo $arg;//輸出hello
$arg = "bye";
}
這樣參數設定爲引用類型,你可以在run裏面改變原始變量的值。

二、插件
看了上面的行爲,我們可以總結出一個模式:
定義不同的行爲,執行同一個方法run
而插件呢?
它是可以定義run的,並且相當於在一個行爲類裏面可以有多個入口,這些入口在不同的條件下觸發。
假設我們在tags.php裏面添加了這樣一個鉤子
'showflash' => array('test'),
注意與行爲的區別,註冊行爲需要包含命名空間也就是反斜槓 \\,當沒有反斜槓,只有一個單詞的時候將認爲是一個插件。
插件定義在 Application/Addons/插件名/插件名Addon.class.php
比如上面的test插件就是 Application/Addons/test/testAddon.class.php
插件類的定義:
<?php
namespace Addons\test;
class testAddon{
function showflash(){
echo "這是插件執行入口";
}
}
?>
可以看到一個明顯的區別,就是run入口變成了 showflash,和鉤子名相同。
有人疑問這樣有什麼用嗎?請繼續往下看:

上面我們只定義了一個插件鉤子 showflash,假如我們再來一個鉤子:

'clearflash'=>array('test');

看到沒?這個鉤子裏面同樣註冊了一個test插件,而這個test還是上面那個testAddon類,不同的是,你需要爲這個clearflash定義一個入口方法,於是testAddon類變成了:
<?php
namespace Addons\test;
class testAddon{
function showflash(){
echo "這是插件執行入口";
}

function clearflash(){
echo "這是另外一個插件鉤子入口";
}
}
?>
這樣當你不同的鉤子註冊了同一個插件類時,你需要在插件類裏面爲這些鉤子分別定義入口方法。
而行爲類則不是,行爲類不管你是不是同一個鉤子,它只認準run方法。
這就是行爲和插件的區別。


文章到這裏就結束了。

寫了這麼多,下班喫飯去也,有不明白的可以留言。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章