Yii的事件和行为的区别和应用

关于 Yii 的事件和行为的描述,可参考 http://www.yiiframework.com/doc/api/1.1/CComponent

事件

事件模型就是设计模式中的“观察者模式”:当对象的状态发生了变化,那么这个对象可以将该事件通知其它对象。

为了使用事件模型,需要实现这三个步骤:1、定义事件;2、注册事件句柄;3、触发事件。

为什么要做这三个步骤呢?因为对于 PHP 本身,它的执行过程不是以进程化来运行的,

所以 Yii 的事件触发机制不会像 ActionScript 3+ 那样,直接将触发事件。

有人说,Yii 的事件概念跟 js 中的事件概念差不多,因为 Yii 是将事件绑定到 Yii::app() 的执行过程中。

由于本人对于 js 的事件没有做过深入的了解,这里不敢贸然否定,或者肯定。

费话少说,先看这样的应用场景:

我想在请求过来的时候,先将请求的 IP 的记录到数据库,然后才进行对应的相应的请求处理。

1. 通过编辑 components/Controller.php 的构造方法来处理。

lass Controller extends CController
{
    public function __construct()
    {
        parent::__construct();
        //将请求的 IP 记录到数据库
    }
}

2. 通过使用事件来处理。

我们来分析一个 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));
}

从代码可以看出来,在处理请求之前,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,写如下代码

/**
 * 自己定义发送邮件事件
 * @param unknown_type $event
 */
public function onSendMail($event)
{
    $this->raiseEvent(‘onSendMail‘,$event);
}  

/**
 * 验证成功,执行
 * @see CModel::afterValidate()
 */
public function afterValidate()
{
    if($this->hasEventHandler(‘onSendMail‘))
        $this->onSendMail(new CEvent($this));
}

这里我们定义了一个 onSendMail 事件,并在 Validate 验证后,触发此事件。

打开 controllers/SiteController.php,将修改actionContact修改为以下内容

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 点,虽然通过绑定事件来做一些额外的处理,但同时已经暴露了一个问题,就是协同开发的时候,我不一定知道,

其他开发人员写了哪些事件的 PHP 回调,在处理过程中到底会调用哪些事件的 PHP 回调。或者说,这个 PHP 回调在什么时候创建的,

或者说你在为组件添加事件处理函数时,找不到合适的时候,如果添加早了,组件还没创建,如果添加晚了,事件不被执行,有可能组件已经执行完了。我们需要一个类似于配置文件的东西,将存在的事件处理组织起来,统一管理。这个时候,行为可以用上了。

行为

这里先重新描述一下为什么要使用行为。

有两种办法可以对类添加特性:

1、直接修改这个类的代码,添加一些成员函数和成员变量;

2、派生,通过子类来扩展。

很明显第二种方法更加易维护、易扩展。但是如果需要对一个类添加多个特性(多人在不同时期),那么需要进行多级派生,这显然加大了维护成本。

在 Yii 里面,通过行为类绑定,组件将一个或多个 CBehavior 类的成员方法和成员变量添加到自己身上,并且在不需要的时候载掉某些 CBehavior 类。

同时,可以通过重写 CBehavior::events 的方法,来实现对目标类的多个事件绑定。这些事件将会在当前行为绑定到目标类的时候,一起被绑定上。

下面我们以代码来具体看一下这个行为特性。

在 protected 创建目录 behaviors,并在protected/behaviors目录下创建ApplicationBehavior.php,输入如下代码:

public function events()
    {
        return array_merge(parent::events(),array(
                ‘onBeginRequest‘=>‘beginRequest‘
        ));
    }  

    public function beginRequest($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 的事件和行为有一定的了解。

转载来自:HDR

时间: 2024-10-20 10:58:54

Yii的事件和行为的区别和应用的相关文章

总结oninput、onchange与onpropertychange事件的用法和区别 书写搜索的神奇代码

总结oninput.onchange与onpropertychange事件的用法和区别 最近手机开发一个模糊搜索的功能组建,在网上就找到这篇文章! 前端页面开发的很多情况下都需要实时监听文本框输入,比如腾讯微博编写140字的微博时输入框hu9i动态显示还可以输入的字数.过去一般都使用onchange/onkeyup/onkeypress/onkeydown实现,但是这存在着一些不好的用户体验.比如onchange事件只在键盘或者鼠标操作改变对象属性,且失去焦点时触发,脚本触发无效:而onkeyd

C# 事件与委托的区别

C# 事件与委托的区别 先看一段程序 class Program { static void Main(string[] args) { Test obj = new Test(); obj.print += printout1; //绑定printout1方法 obj.print += printout2; //绑定printout2方法 obj.start(); } static void printout1() { Console.WriteLine("输出第一段字符串"); }

清晰理解Yii的事件和行为--假如你翻了十多页百度搜索结果还是一无所获的话:)

编程也许真的是个技术活,每次你被概念搞的蒙头转向,无从下手的时候你也许会这么想.但这也就是一会会的事,如果你在晚上喝着茶,咬着牙,僵硬着脖子,一页一页的点百度,然后在笔记上一句话一句话的记下你看到的每一篇文章中看懂了的那一句,我想很快那一句一句的积累会把你带到一个恍然大悟的时刻.这点请你务必相信.但前提是,你翻了十多页的百度看到的相关文章大部分是不重复的....... 总结:上面一段话说了两件事,1柳暗花明是确定是可以常常有的,2百度是确定让人很恼火的. 再总结:上面都是废话,下面开始干货. 让

html5与js关于input[type='text']文本框value改变触发事件一些属性的区别oninput,onpropertychange,onchange和文本框的value点击全选状态onclick="select();"。做购物车页面时会要用到。

关于input[type='text']文本框value改变触发事件一些属性的区别oninput,onpropertychange,onchange和文本框的点击全选状态onclick="select();".做购物车页面时会要用到. input[type='text']文本框value改变触发事件一些属性的区别oninput,onpropertychange,onchange: 1.onchange事件与onpropertychange事件的区别:onchange事件在内容改变(两次

NewRowNeeded和UserAddedRow事件以及RowsAdded的区别使用

NewRowNeeded事件当 VirtualMode 属性为 true 时,将在用户定位到 DataGridView 底部的新行时发生,适合给新行建立一些默认数据和按规则应该产生的数据,但此时不推荐添加新数据到后台数据表中.因为用户操作有太多的变数,可以把产生的默认值直接赋值给一个临时初始数据对像即可,在用户触发UserAddedRow事件后,再赋值到后台数据也不迟 Private pInitData As OuterExtendItem Private Sub xDataGridView_N

Yii 2.x 和1.x区别以及yii2.0安装

知乎上有个类似的问题:http://www.zhihu.com/question/22924271/answer/23085751 大致思路不会变,开发流程变化也不是很大.有变化的是1.yii2带入的PHP5.4的特性,引入了namespace解决命名冲突,因此基类不会再C字开头了2.不再所有类都继承自组件Component,而是选择继承object和component(也继承自object,但带有事件功能.以及用于扩展的Behavior功能)3.更加的MVC,原先的view层其实基本算是con

总结oninput、onchange与onpropertychange事件的用法和区别

前端页面开发的很多情况下都需要实时监听文本框输入,比如腾讯微博编写140字的微博时输入框hu9i动态显示还可以输入的字数.过去一般都使用onchange/onkeyup/onkeypress/onkeydown实现,但是这存在着一些不好的用户体验.比如onchange事件只在键盘或者鼠标操作改变对象属性,且失去焦点时触发,脚本触发无效:而onkeydown/onkeypress/onkeyup在处理复制.粘贴.拖拽.长按键(按住键盘不放)等细节上并不完善. onpropertychange属性可

事件和方法的区别

事件:指的是一个类有可能会引发的一个调用,任何类都可以向一个有事件的类注册这个事件的监听,那么当事件引发时,类就会受到事件通知,从而响应. 方法:指的是一个类的一些操作,比如一个Car类他有一个Move的移动方法,表示这个车子可以移动的操作(Operation). 对于BOM对象可有方法和事件,其区别在于: 1.事件名前一般都以on开头. 2.方法是程序员写语句直接调用,即显示调用:事件不需程序员调用,但是,必须由程序员写一个函数且将该函数赋值给相应的事件,其调用是在相应的事件触发时.

DOM事件对象、IE事件对象、旧浏览器事件对象的JavaScript区别

事件流: 事件冒泡:即事件最开始由最具体的元素(文档中嵌套层次最深的那个节点)接收,然后逐级向上传播至最不具体的那个节点(文档). 事件捕获:不太具体的节点应该更早接收到事件,而最具体的节点最后接收到事件. DOM2级事件处理程序: .addEventListener();      .removeEventListener(); 在IE浏览器中不起作用!IE事件处理程序: .attachEvent();     .detachEvent(); 跨浏览器常用事件处理程序: var eventUt