本文實(shí)例講述了Yii Framework框架中事件和行為的區(qū)別及應(yīng)用。分享給大家供大家參考,具體如下:
個(gè)人覺得,在 Yii 里面,最難以明白的就是事件(Event)和行為(behavior)了。這不僅僅是因?yàn)樗鼈兊母拍?/p>
比較難明,關(guān)鍵是它們的應(yīng)用場(chǎng)景比較難明,不知道什么時(shí)候應(yīng)該使用事件和行為來開發(fā)。
關(guān)于 Yii 的事件和行為的描述,可參考 http://www.yiiframework.com/doc/api/1.1/CComponent
本文參考的文章:
http://www.larryullman.com/2010/07/20/forcing-login-for-all-pages-in-yii/
http://www.yiiframework.com/wiki/44/behaviors-events/
事件
事件模型就是設(shè)計(jì)模式中的“觀察者模式”:當(dāng)對(duì)象的狀態(tài)發(fā)生了變化,那么這個(gè)對(duì)象可以將該事件通知其它對(duì)象。
為了使用事件模型,需要實(shí)現(xiàn)這三個(gè)步驟:1、定義事件;2、注冊(cè)事件句柄;3、觸發(fā)事件。
為什么要做這三個(gè)步驟呢?因?yàn)閷?duì)于 PHP 本身,它的執(zhí)行過程不是以進(jìn)程化來運(yùn)行的,
所以 Yii 的事件觸發(fā)機(jī)制不會(huì)像 ActionScript 3+ 那樣,直接將觸發(fā)事件。
有人說,Yii 的事件概念跟 js 中的事件概念差不多,因?yàn)?Yii 是將事件綁定到 Yii::app() 的執(zhí)行過程中。
由于本人對(duì)于 js 的事件沒有做過深入的了解,這里不敢貿(mào)然否定,或者肯定。
費(fèi)話少說,先看這樣的應(yīng)用場(chǎng)景:
我想在請(qǐng)求過來的時(shí)候,先將請(qǐng)求的 IP 的記錄到數(shù)據(jù)庫(kù),然后才進(jìn)行對(duì)應(yīng)的相應(yīng)的請(qǐng)求處理。
1. 通過編輯 components/Controller.php 的構(gòu)造方法來處理。
如代碼:
class Controller extends CController
{
public function __construct()
{
parent::__construct();
//將請(qǐng)求的 IP 記錄到數(shù)據(jù)庫(kù)
}
}
2. 通過使用事件來處理。
我們來分析一個(gè) framework/base/CApplication.php 的 run() 方法
public function run()
{
if($this->hasEventHandler('onBeginRequest'))
$this->onBeginRequest(new CEvent($this));
$this->processRequest();
if($this->hasEventHandler('onEndRequest'))
$this->onEndRequest(new CEvent($this));
}
從代碼可以看出來,在處理請(qǐng)求之前,Yii 首先會(huì)判斷一下當(dāng)前有沒有處理 onBeginRequest 的函數(shù)或者類的方法綁定了,
如果有這樣的函數(shù)或者類的方法存在,則先執(zhí)行了它們,然后再處理請(qǐng)求。
那么,怎樣寫 onBeginRequest,或者怎樣去調(diào)用呢?
方法一:修改 index.php
一般來說,我們的 index.php 最后一句是:
Yii::createWebApplication($config)->run();
我們?cè)谶@里將它改造一下,改成:
$app = Yii::createWebApplication($config);
Yii::app()->onBeginRequest=function($event) {
//將請(qǐng)求的 IP 記錄到數(shù)據(jù)庫(kù)
};
Yii::app()->onBeginRequest=function($event) {
//其它的你想要處理的內(nèi)容,比如說,生成一個(gè)文件
//file_put_contents('onBeginRequest.txt', '阿媽,我得左啦!');
};
$app->run();
方法二:在配置文件 main.php 里面注冊(cè)事件
如:
/***************************************************
在我們想要的內(nèi)容的前后出現(xiàn)了這些代碼
只是為了說明,我們添加的內(nèi)容是要放在
這個(gè)配置數(shù)據(jù)的一維里面。
'import'=>array(
'application.models.*',
'application.components.*',
'application.helpers.*',
),
'defaultController'=>'post',
***************************************************/
//其它代碼
'import'=>array(
'application.models.*',
'application.components.*',
'application.helpers.*',
),
/************** 這才是我們想要添加的代碼 **************/
'onBeginRequest' => array('MyEventHandler', 'MyEventHandlerMethod'),
'defaultController'=>'post',
//其它代碼
關(guān)于 onBeginRequest 的使用,它必須是一個(gè)有效的 PHP 回調(diào)。
即,一個(gè)指匿名函數(shù),全局函數(shù)名的字符串或一個(gè)數(shù)組。如果是數(shù)組,那么該數(shù)組包含兩個(gè)元素,第一個(gè)元素是一個(gè)對(duì)象,第二個(gè)元素是這個(gè)對(duì)象的方法。
由此可見,方法一和方法二還是有點(diǎn)區(qū)別的。使用方法二的時(shí)候,只能注冊(cè)一個(gè) PHP 回調(diào),而使用方法一,可以是不同的 PHP 回調(diào)。當(dāng)然,這里說的方法二
只能注冊(cè)一個(gè) PHP 回調(diào)是指,對(duì)整個(gè)請(qǐng)求處理過程中肯定會(huì)執(zhí)行的 PHP 回調(diào),在其它地方需要的時(shí)候,也可以加上你想實(shí)現(xiàn)的功能。
3. 另一個(gè)例子,來說明自己是怎樣定義一個(gè)事件的。
打開 models/ContactForm.php,輸入
/**
* 自己定義發(fā)送郵件事件
* @param unknown_type $event
*/
public function onSendMail($event)
{
$this->raiseEvent('onSendMail',$event);
}
/**
* 驗(yàn)證成功,執(zhí)行
* @see CModel::afterValidate()
*/
public function afterValidate()
{
if($this->hasEventHandler('onSendMail'))
$this->onSendMail(new CEvent($this));
}
這里我們定義了一個(gè) onSendMail 事件,并在 Validate 驗(yàn)證后,觸發(fā)此事件。
打開 controllers/SiteController.php,將修改actionContact修改為以下內(nèi)容
public function actionContact()
{
$model=new ContactForm;
$model->onSendMail=function($event) {
$headers="From: {$event->sender->email}\r\nReply-To: {$event->sender->email}";
mail(Yii::app()->params['adminEmail'],$event->sender->subject,$event->sender->body,$headers);
};
if(isset($_POST['ContactForm']))
{
$model->attributes=$_POST['ContactForm'];
if($model->validate())
{
Yii::app()->user->setFlash('contact','Thank you for contacting us. We will respond to you as soon as possible.');
$this->refresh();
}
}
$this->render('contact',array('model'=>$model));
}
上面的 3 點(diǎn),雖然通過綁定事件來做一些額外的處理,但同時(shí)已經(jīng)暴露了一個(gè)問題,就是協(xié)同開發(fā)的時(shí)候,我不一定知道,
其他開發(fā)人員寫了哪些事件的 PHP 回調(diào),在處理過程中到底會(huì)調(diào)用哪些事件的 PHP 回調(diào)?;蛘哒f,這個(gè) PHP 回調(diào)在什么時(shí)候創(chuàng)建的,
或者說你在為組件添加事件處理函數(shù)時(shí),找不到合適的時(shí)候,如果添加早了,組件還沒創(chuàng)建,如果添加晚了,事件不被執(zhí)行,有可能組件已經(jīng)執(zhí)行完了。
我們需要一個(gè)類似于配置文件的東西,將存在的事件處理組織起來,統(tǒng)一管理。這個(gè)時(shí)候,行為可以用上了。
行為
這里先重新描述一下為什么要使用行為。
有兩種辦法可以對(duì)類添加特性:
1、直接修改這個(gè)類的代碼,添加一些成員函數(shù)和成員變量;
2、派生,通過子類來擴(kuò)展。
很明顯第二種方法更加易維護(hù)、易擴(kuò)展。但是如果需要對(duì)一個(gè)類添加多個(gè)特性(多人在不同時(shí)期),那么需要進(jìn)行多級(jí)派生,這顯然加大了維護(hù)成本。
在 Yii 里面,通過行為類綁定,組件將一個(gè)或多個(gè) CBehavior 類的成員方法和成員變量添加到自己身上,并且在不需要的時(shí)候載掉某些 CBehavior 類。
同時(shí),可以通過重寫 CBehavior::events 的方法,來實(shí)現(xiàn)對(duì)目標(biāo)類的多個(gè)事件綁定。這些事件將會(huì)在當(dāng)前行為綁定到目標(biāo)類的時(shí)候,一起被綁定上。
下面我們以代碼來具體看一下這個(gè)行為特性。
在 protected 創(chuàng)建目錄 behaviors,并在protected/behaviors目錄下創(chuàng)建ApplicationBehavior.php,輸入如下代碼:
?php
class ApplicationBehavior extends CBehavior
{
public function events()
{
return array_merge(parent::events(),array(
'onBeginRequest'=>'beginRequest'
));
}
public function beginRequest($event)
{
echo "我已經(jīng)將 onBeginRequest 的事件處理通過行為綁定了";
}
}
此行為文件,是要為 CApplication 服務(wù),仔細(xì)查看這個(gè)行為文件,我們可以看到,events 方法定義了些行為可以處理的事件,
上面的類,可以處理 onBeginRequest 事件,當(dāng)然如果你自己定義的組件也有一個(gè)叫做 onBeginRequest 方法,你也可以使用此行為
后面的 beginRequest 就是事件的處理函數(shù),這個(gè)處理函數(shù)必須要有行為類中定義。
跟上面的事件一樣,也有兩種方法將此行為類附加到 CApplication。
方法一:
打開 index.php,輸入下面代碼
$app = Yii::createWebApplication($config);
Yii::app()->onBeginRequest=function($event) {
//將請(qǐng)求的 IP 記錄到數(shù)據(jù)庫(kù)
};
Yii::app()->onBeginRequest=function($event) {
//file_put_contents('onBeginRequest.txt', '阿媽,我又得左啦!');
};
/****** 這句才是我們想要的東東 *********/
$app->attachBehavior('app', 'application.behaviors.ApplicationBehavior');
$app->run();
刷新頁(yè)面,你將會(huì)在頭部看到一行 “我已經(jīng)將 onBeginRequest 的事件處理通過行為綁定了”
方法二:
如果對(duì) Yii 的組件定義了解的話,應(yīng)該知道每一個(gè)組件,都有一個(gè)behaviors方法,該方法中定義的相關(guān)行為,在組件初始化時(shí),會(huì)自動(dòng)附件,
下面我們就為 CApplication 定義 behaviors,由于 CApplication 是系統(tǒng)級(jí)類,我們可以擴(kuò)展此類,并添加behaviors方法。這里補(bǔ)充一下,
CApplication 是會(huì)根據(jù) config/main.php 配置進(jìn)行初始化,那么我們就可以將 behaviors 定義在 main.php。
打開 protected/config/main.php,加入如下代碼:
'behaviors' => array(
'app' => 'application.behaviors.ApplicationBehavior',
),
刷新頁(yè)面,你也會(huì)在頭部看到一行 “我已經(jīng)將 onBeginRequest 的事件處理通過行為綁定了”
通過以上的例子,希望相關(guān)讀者對(duì) Yii 的事件和行為有一定的了解。
更多關(guān)于Yii相關(guān)內(nèi)容感興趣的讀者可查看本站專題:《Yii框架入門及常用技巧總結(jié)》、《php優(yōu)秀開發(fā)框架總結(jié)》、《smarty模板入門基礎(chǔ)教程》、《php面向?qū)ο蟪绦蛟O(shè)計(jì)入門教程》、《php字符串(string)用法總結(jié)》、《php+mysql數(shù)據(jù)庫(kù)操作入門教程》及《php常見數(shù)據(jù)庫(kù)操作技巧匯總》
希望本文所述對(duì)大家基于Yii框架的PHP程序設(shè)計(jì)有所幫助。
您可能感興趣的文章:- 從零開始學(xué)YII2框架(六)高級(jí)應(yīng)用程序模板
- yii2高級(jí)應(yīng)用之自定義組件實(shí)現(xiàn)全局使用圖片上傳功能的方法
- YII Framework框架使用YIIC快速創(chuàng)建YII應(yīng)用之migrate用法實(shí)例詳解
- YII Framework框架教程之使用YIIC快速創(chuàng)建YII應(yīng)用詳解
- Yii2框架redis基本應(yīng)用示例
- Yii框架學(xué)習(xí)筆記之應(yīng)用組件操作示例
- Yii框架常見緩存應(yīng)用實(shí)例小結(jié)
- 再談Yii Framework框架中的事件event原理與應(yīng)用
- Yii框架應(yīng)用組件用法實(shí)例分析
- Yii 框架應(yīng)用(Applications)操作實(shí)例詳解