Yii Framework框架中事件和行为的区别及应用实例分析
本文实例讲述了YiiFramework框架中事件和行为的区别及应用。分享给大家供大家参考,具体如下:
个人觉得,在Yii里面,最难以明白的就是事件(Event)和行为(behavior)了。这不仅仅是因为它们的概念
比较难明,关键是它们的应用场景比较难明,不知道什么时候应该使用事件和行为来开发。
关于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/
事件
事件模型就是设计模式中的“观察者模式”:当对象的状态发生了变化,那么这个对象可以将该事件通知其它对象。
为了使用事件模型,需要实现这三个步骤:1、定义事件;2、注册事件句柄;3、触发事件。
为什么要做这三个步骤呢?因为对于PHP本身,它的执行过程不是以进程化来运行的,
所以Yii的事件触发机制不会像ActionScript3+那样,直接将触发事件。
有人说,Yii的事件概念跟js中的事件概念差不多,因为Yii是将事件绑定到Yii::app()的执行过程中。
由于本人对于js的事件没有做过深入的了解,这里不敢贸然否定,或者肯定。
费话少说,先看这样的应用场景:
我想在请求过来的时候,先将请求的IP的记录到数据库,然后才进行对应的相应的请求处理。
1.通过编辑components/Controller.php的构造方法来处理。
如代码:
classControllerextendsCController { publicfunction__construct() { parent::__construct(); //将请求的IP记录到数据库 } }
2.通过使用事件来处理。
我们来分析一个framework/base/CApplication.php的run()方法
publicfunctionrun() { if($this->hasEventHandler('onBeginRequest')) $this->onBeginRequest(newCEvent($this)); $this->processRequest(); if($this->hasEventHandler('onEndRequest')) $this->onEndRequest(newCEvent($this)); }
从代码可以看出来,在处理请求之前,Yii首先会判断一下当前有没有处理onBeginRequest的函数或者类的方法绑定了,
如果有这样的函数或者类的方法存在,则先执行了它们,然后再处理请求。
那么,怎样写onBeginRequest,或者怎样去调用呢?
方法一:修改index.php
一般来说,我们的index.php最后一句是:
Yii::createWebApplication($config)->run();
我们在这里将它改造一下,改成:
$app=Yii::createWebApplication($config); Yii::app()->onBeginRequest=function($event){ //将请求的IP记录到数据库 }; Yii::app()->onBeginRequest=function($event){ //其它的你想要处理的内容,比如说,生成一个文件 //file_put_contents('onBeginRequest.txt','阿妈,我得左啦!'); }; $app->run();
方法二:在配置文件main.php里面注册事件
如:
/*************************************************** 在我们想要的内容的前后出现了这些代码 只是为了说明,我们添加的内容是要放在 这个配置数据的一维里面。 'import'=>array( 'application.models.*', 'application.components.*', 'application.helpers.*', ), 'defaultController'=>'post', ***************************************************/ //其它代码 'import'=>array( 'application.models.*', 'application.components.*', 'application.helpers.*', ), /**************这才是我们想要添加的代码**************/ 'onBeginRequest'=>array('MyEventHandler','MyEventHandlerMethod'), 'defaultController'=>'post', //其它代码
关于onBeginRequest的使用,它必须是一个有效的PHP回调。
即,一个指匿名函数,全局函数名的字符串或一个数组。如果是数组,那么该数组包含两个元素,第一个元素是一个对象,第二个元素是这个对象的方法。
由此可见,方法一和方法二还是有点区别的。使用方法二的时候,只能注册一个PHP回调,而使用方法一,可以是不同的PHP回调。当然,这里说的方法二
只能注册一个PHP回调是指,对整个请求处理过程中肯定会执行的PHP回调,在其它地方需要的时候,也可以加上你想实现的功能。
3.另一个例子,来说明自己是怎样定义一个事件的。
打开models/ContactForm.php,输入
/** *自己定义发送邮件事件 *@paramunknown_type$event */ publicfunctiononSendMail($event) { $this->raiseEvent('onSendMail',$event); } /** *验证成功,执行 *@seeCModel::afterValidate() */ publicfunctionafterValidate() { if($this->hasEventHandler('onSendMail')) $this->onSendMail(newCEvent($this)); }
这里我们定义了一个onSendMail事件,并在Validate验证后,触发此事件。
打开controllers/SiteController.php,将修改actionContact修改为以下内容
publicfunctionactionContact() { $model=newContactForm; $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','Thankyouforcontactingus.Wewillrespondtoyouassoonaspossible.'); $this->refresh(); } } $this->render('contact',array('model'=>$model)); }
上面的3点,虽然通过绑定事件来做一些额外的处理,但同时已经暴露了一个问题,就是协同开发的时候,我不一定知道,
其他开发人员写了哪些事件的PHP回调,在处理过程中到底会调用哪些事件的PHP回调。或者说,这个PHP回调在什么时候创建的,
或者说你在为组件添加事件处理函数时,找不到合适的时候,如果添加早了,组件还没创建,如果添加晚了,事件不被执行,有可能组件已经执行完了。
我们需要一个类似于配置文件的东西,将存在的事件处理组织起来,统一管理。这个时候,行为可以用上了。
行为
这里先重新描述一下为什么要使用行为。
有两种办法可以对类添加特性:
1、直接修改这个类的代码,添加一些成员函数和成员变量;
2、派生,通过子类来扩展。
很明显第二种方法更加易维护、易扩展。但是如果需要对一个类添加多个特性(多人在不同时期),那么需要进行多级派生,这显然加大了维护成本。
在Yii里面,通过行为类绑定,组件将一个或多个CBehavior类的成员方法和成员变量添加到自己身上,并且在不需要的时候载掉某些CBehavior类。
同时,可以通过重写CBehavior::events的方法,来实现对目标类的多个事件绑定。这些事件将会在当前行为绑定到目标类的时候,一起被绑定上。
下面我们以代码来具体看一下这个行为特性。
在protected创建目录behaviors,并在protected/behaviors目录下创建ApplicationBehavior.php,输入如下代码:
'beginRequest' )); } publicfunctionbeginRequest($event) { echo"我已经将onBeginRequest的事件处理通过行为绑定了"; } }
此行为文件,是要为CApplication服务,仔细查看这个行为文件,我们可以看到,events方法定义了些行为可以处理的事件,
上面的类,可以处理onBeginRequest事件,当然如果你自己定义的组件也有一个叫做onBeginRequest方法,你也可以使用此行为
后面的beginRequest就是事件的处理函数,这个处理函数必须要有行为类中定义。
跟上面的事件一样,也有两种方法将此行为类附加到CApplication。
方法一:
打开index.php,输入下面代码
$app=Yii::createWebApplication($config); Yii::app()->onBeginRequest=function($event){ //将请求的IP记录到数据库 }; Yii::app()->onBeginRequest=function($event){ //file_put_contents('onBeginRequest.txt','阿妈,我又得左啦!'); }; /******这句才是我们想要的东东*********/ $app->attachBehavior('app','application.behaviors.ApplicationBehavior'); $app->run();
刷新页面,你将会在头部看到一行“我已经将onBeginRequest的事件处理通过行为绑定了”
方法二:
如果对Yii的组件定义了解的话,应该知道每一个组件,都有一个behaviors方法,该方法中定义的相关行为,在组件初始化时,会自动附件,
下面我们就为CApplication定义behaviors,由于CApplication是系统级类,我们可以扩展此类,并添加behaviors方法。这里补充一下,
CApplication是会根据config/main.php配置进行初始化,那么我们就可以将behaviors定义在main.php。
打开protected/config/main.php,加入如下代码:
'behaviors'=>array( 'app'=>'application.behaviors.ApplicationBehavior', ),
刷新页面,你也会在头部看到一行“我已经将onBeginRequest的事件处理通过行为绑定了”
通过以上的例子,希望相关读者对Yii的事件和行为有一定的了解。
更多关于Yii相关内容感兴趣的读者可查看本站专题:《Yii框架入门及常用技巧总结》、《php优秀开发框架总结》、《smarty模板入门基础教程》、《php面向对象程序设计入门教程》、《php字符串(string)用法总结》、《php+mysql数据库操作入门教程》及《php常见数据库操作技巧汇总》
希望本文所述对大家基于Yii框架的PHP程序设计有所帮助。