文档章节

Yii框架 Event 和 Behavior理解

蔚蓝SG
 蔚蓝SG
发布于 2015/04/28 15:07
字数 1449
阅读 32
收藏 0
点赞 0
评论 0

Event 

    Yii中的Event由两部分组成,分别是$events和EventHandler,其中$event代表事件发生时的具体数据,而EventHandler代表事件发生时的具体的处理函数。

    因此,当错误发生时,直接调用onError函数就可以,这时,之前被注册过的onError这个事件对应的错误处理函数都会被执行。具体的ErrorHandler发生过程可以通过raiseEvent()的源代码来了解。

    在Yii中,Event通常是在CComponent的子类中扩展出来的,一般以on开头,如:

    public function onError($event)

    {

            $this->raiseEvent('onError', $event);

    }

public function raiseEvent($name,$event)  
 {  
     $name=strtolower($name);  
     if(isset($this->_e[$name]))  
     {  
         foreach($this->_e[$name] as $handler)  
         {  
             if(is_string($handler))  
                 call_user_func($handler,$event);  
             else if(is_callable($handler,true))  
             {  
                 if(is_array($handler))  
                 {  
                     // an array: 0 - object, 1 - method name  
                     list($object,$method)=$handler;  
                     if(is_string($object))    // static method call  
                         call_user_func($handler,$event);  
                     else if(method_exists($object,$method))  
                         $object->$method($event);  
                     else  
                         throw new CException(Yii::t('yii','Event "{class}.{event}" is attached with an invalid handler "{handler}".',  
                             array('{class}'=>get_class($this), '{event}'=>$name, '{handler}'=>$handler[1])));  
                 }  
                 else // PHP 5.3: anonymous function  
                     call_user_func($handler,$event);  
             }  
             else  
                 throw new CException(Yii::t('yii','Event "{class}.{event}" is attached with an invalid handler "{handler}".',  
                     array('{class}'=>get_class($this), '{event}'=>$name, '{handler}'=>gettype($handler))));  
             // stop further handling if param.handled is set true  
             if(($event instanceof CEvent) && $event->handled)  
                 return;  
         }  
     }  
     else if(YII_DEBUG && !$this->hasEvent($name))  
         throw new CException(Yii::t('yii','Event "{class}.{event}" is not defined.',  
             array('{class}'=>get_class($this), '{event}'=>$name)));  
 }

    此函数的主要内容就是在CComponent的变量$_e寻找与事件名称(如本例中的'onError')对应的EventHandler(函数),然后调用该EventHandler,同时将事件发生时的数据作为参数传递给该函数,完成事件的处理。

    那么既然有EventHandler的调用,那么肯定就会有Event和EventHandler的注册了,否则就没有EventHandler可调用。

说到注册,自然会想到CComponent类中的__set()函数了,来看一下__set()函数的源码:

 public function __set($name,$value)  
         {  
                 $setter='set'.$name;  
                 if(method_exists($this,$setter))  
                         return $this->$setter($value);  
                 else if(strncasecmp($name,'on',2)===0 && method_exists($this,$name))  
                 {  
                         // duplicating getEventHandlers() here for performance  
                         $name=strtolower($name);  
                         if(!isset($this->_e[$name]))  
                                 $this->_e[$name]=new CList;  
                         return $this->_e[$name]->add($value);  
                 }  
                 else if(is_array($this->_m))  
                 {  
                         foreach($this->_m as $object)  
                         {  
                                 if($object->getEnabled() && (property_exists($object,$name) || $object->canSetProperty($name)))  
                                         return $object->$name=$value;  
                         }  
                 }  
                 if(method_exists($this,'get'.$name))  
                         throw new CException(Yii::t('yii','Property "{class}.{property}" is read only.',  
                                 array('{class}'=>get_class($this), '{property}'=>$name)));  
                 else  
                         throw new CException(Yii::t('yii','Property "{class}.{property}" is not defined.',  
                                 array('{class}'=>get_class($this), '{property}'=>$name)));  
         }

    关于Event事件的注册是从第6行开始,从代码中可以看出Event名称必须以'on'开头,如onError,onClick等。对应的$value是一个List,即可以有多个EventHandler。

    具体的注册代码,Yii注释中也已经给出:

$component->onClick=$callback;    // or $component->onClick->add($callback);  

    总结一下,Event的原理就是首先要定义一个事件处理函数,其次将其注册到该类的对应的事件中去,最后在发生事件时调用该事件的EventHandler。实例如下,当改变类中的变量name时,打印字符串:

  class example extends CComponent
  {
        private $name;
        public function getName()
        {
            return isset($name) ? $name : '';
        }
        public function setName($newName)
        {
            $this->name = $newName;
            $this->raiseEvent('onChange', new CEvent());
        }
  }   
  //在某一controller中实现:
  $exa = new example();
  $exa->onChange = array($this, "showChange");
  $exa->setName("zhangsan");
  
  public function showChange()
  {
        echo "changed";
  }

Behavior

    Behavior是一种跟EventHandler功能比较类似的另一种表现形式,有点类似于多重继承,通过类绑定的方法,component将一个或者多个CBehavior类的成员方法和变量绑定到自己身上。

    通过调用CComponet中的attachBehavior方法实现关联,我们深入起源码看看究竟做了什么?

public function attachBehavior($name,$behavior)  //$name:行为名称 $behavior:行为对象
 {  
     if(!($behavior instanceof IBehavior))  
         $behavior=Yii::createComponent($behavior);  
     $behavior->setEnabled(true);  
     $behavior->attach($this);  
     return $this->_m[$name]=$behavior;  
 }

    程序很短,就是判断传入的behaviour是不是IBehavior的实例,根据情况做一下处理,反正最后是通过调用IBehavior的attach方法去挂到当前的CComponent方法。

    好了,关键的地方来了。注意看第七行,没有错,起把传入的behavior传入了 $this->_m[$name]变量,这个也就是为什么可以多绑定的原因,实现了收集的机制。转入IBehavior看attach方法定义

public function attach($owner)  
{  
    $this->_owner=$owner;  
    foreach($this->events() as $event=>$handler)  
        $owner->attachEventHandler($event,array($this,$handler));  
}

     分析这段代码,首先可以看出对于每一个Behavior,都只能属于一个Component.

       那么Event和Behavior又怎么会有关系了?看到 $owner->attachEventHandler($event,array($this,$handler));这句了吗?$owner就是我们绑定behavior的component,用该方法的名称就可以很容易的发现这里实现的Event Handler的绑定功能。

       这里的$this->events()是什么?

public function events()  
        {  
                return array();  
        }

         怎么突然和上面匹配不了了?返回了一个空的array()?千万别搞错,这个函数是一个virtual的函数是需要重写的。你其实这里就可以理解为events()方法返回的是一个含有事件名称和事件处理方法的关联数组。

        如果还不能理解,我们看下CModelBehavior的这段的具体实现,他可是继承自CBehavior的。

public function events()  
{  
    return array(  
        'onAfterConstruct'=>'afterConstruct',  
        'onBeforeValidate'=>'beforeValidate',  
        'onAfterValidate'=>'afterValidate',  
    );  
}

    看到了吗?定义了三个事件,以及相应的事件处理函数,只是这些事件处理函数,在你扩展的时候,需要重写。

    总结一下,behavior其实与event很类似,只不过behavior是将事件分类整理到一起,归到一个类中,然后一起注册给component,因此behavior可以看做是一个事件与事件处理函数的集合。需要注意的是,当一个behavior被attach到一个component时,该behavior的所有函数都能被component调用。具体事例如下:

    首先重写Behavior类:

    class exampleBehavior extends CBehavior
    {
            //重写关联数组
            public function events()
            {
                    return array(
                            'onBegin' => 'begin';
                            'onEnd' => 'end';
                            'onClick' => 'click';
                    );
            }
            //事件处理函数
            public function begin()
            {
            }
            public function end()
            {
            }
            public function click()
            {
            }
    }
   //在某一个controller中实现:
    $exBehavior = new exampleBehavior();
    $component->attachBehavior('example', 'application.behavior.exampleBehavior');
    $component->begin();

 

 

© 著作权归作者所有

共有 人打赏支持
蔚蓝SG
粉丝 2
博文 2
码字总数 1805
作品 0
朝阳
高级程序员
yii2 - Property 之 默认构造方法 和 setter/getter 方法

yii2 内部规定了 construct 函数的构造形式,以键值对儿数组作为参数,进行属性的初始化,但要注意给属性赋值的工作是转交给基类 yiibaseYii::configure 方法的,故无法直接访问本类的私有属...

big_cat
2016/05/27
530
0
yii2 - Behavior 实例及源码分析

Behavior 的简述 行为简单来说是组件的扩展,可以对组件的属性,方法,事件 (yii2组件的三大要点)进行扩展而无需改动组件现有的代码逻辑。即此行为所拥有的属性,方法,事件,都会被绑定它...

big_cat
2016/06/01
811
0
Yii2 源码分析 - 入口文件执行流程

以 yii 2.0.14 高级版的 frontend 为例,从 frontend/web/index.php 开始 入口文件看着就这么几行,简单的很,那他是怎么通过这几行来运行应用的呢?先看 Yii.php 内的逻辑 接下来,就是重头...

botkenni
05/03
0
0
Ethan/yii2-serialized

Yii2 Serialized Attributes Behavior This Yii2 model behavior allows you to store arrays in attributes. To attach the behavior put the following code in your model: public functi......

Ethan
2016/03/28
0
0
Yii 2 —— Backend自动出现登录页

1.1 Backend自动出现登录页 用http://backend/访问后端时,页面会自动被重定向到http://backend/index.php?r=site%2Flogin,要求进行登录,这其中的流程是怎样的? 按照YII的理念,框架在处理...

tywali
2016/11/09
0
0
yii2源码分析之执行基本流程

用yii2框架用了将近2年,一直都没有去看过它底层源码, 马上快不用了,最近对其源码研究一番,哈哈 废话少说,上代码, 入口文件是web/index.php

china_lx1
04/22
0
0
从配置文件的角度去了解Yii2

前言 Yii2是一个奇特的框架,其牺牲了现在盛行的解耦设计,用一个高度耦合的结构提供给开发者一个方便的几类抽象,Application,Module,Component,甚至是ServiceLocator.想让对象具备哪类特征就直...

Vett
2017/12/23
0
0
PHP 命名空间 namespace / 类别名 use / 框架自动载入 机理的

相比 PHP5.2 版本 PHP5.3 新增了三大主要新特性 命名空间 延迟静态绑定 lambda匿名函数 命名空间的出现也使PHP可以更加合理的组织项目结构,同时通过命名空间和自动载入机制一大批 PHP 的 MV...

big_cat
2016/02/02
5.4K
0
Yii框架学习笔记(一)引入Yii框架

Yii Framework是一个基于组件、用于开发大型 Web 应用的高性能 PHP 框架。Yii提供了今日Web 2.0应用开发所需要的几乎一切功能。Yii是最有效率的PHP框架之一。Yii是创始人薛强的心血结晶,于2...

flute小行
2014/04/11
0
0
YII2 刷新网页时验证码不刷新

第一种方法(失败): 修改 fixedVerifyCode 值,确实可以刷新页面的时候改变验证码, 但是 Session 里面没有值,没有值,没有值... public function actions() 1, 第二种方法(成功),网上...

红石头
2015/12/31
703
1

没有更多内容

加载失败,请刷新页面

加载更多

下一页

SpringBoot | 第十章:Swagger2的集成和使用

前言 前一章节介绍了mybatisPlus的集成和简单使用,本章节开始接着上一章节的用户表,进行Swagger2的集成。现在都奉行前后端分离开发和微服务大行其道,分微服务及前后端分离后,前后端开发的...

oKong
今天
4
0
Python 最小二乘法 拟合 二次曲线

Python 二次拟合 随机生成数据,并且加上噪声干扰 构造需要拟合的函数形式,使用最小二乘法进行拟合 输出拟合后的参数 将拟合后的函数与原始数据绘图后进行对比 import numpy as npimport...

阿豪boy
今天
1
0
云拿 无人便利店

附近(上海市-航南路)开了家无人便利店.特意进去体验了一下.下面把自己看到的跟大家分享下. 经得现场工作人员同意后拍了几张照片.从外面看是这样.店门口的指导里强调:不要一次扫码多个人进入....

周翔
昨天
1
0
Java设计模式学习之工厂模式

在Java(或者叫做面向对象语言)的世界中,工厂模式被广泛应用于项目中,也许你并没有听说过,不过也许你已经在使用了。 简单来说,工厂模式的出现源于增加程序序的可扩展性,降低耦合度。之...

路小磊
昨天
163
1
npm profile 新功能介绍

转载地址 npm profile 新功能介绍 npm新版本新推来一个功能,npm profile,这个可以更改自己简介信息的命令,以后可以不用去登录网站来修改自己的简介了 具体的这个功能的支持大概是在6这个版...

durban
昨天
1
0
Serial2Ethernet Bi-redirection

Serial Tool Serial Tool is a utility for developing serial communications, custom protocols or device testing. You can set up bytes to send accordingly to your protocol and save......

zungyiu
昨天
1
0
python里求解物理学上的双弹簧质能系统

物理的模型如下: 在这个系统里有两个物体,它们的质量分别是m1和m2,被两个弹簧连接在一起,伸缩系统为k1和k2,左端固定。假定没有外力时,两个弹簧的长度为L1和L2。 由于两物体有重力,那么...

wangxuwei
昨天
0
0
apolloxlua 介绍

##项目介绍 apolloxlua 目前支持javascript到lua的翻译。可以在openresty和luajit里使用。这个工具分为两种模式, 一种是web模式,可以通过网页使用。另外一种是tool模式, 通常作为大规模翻...

钟元OSS
昨天
2
0
Mybatis入门

简介: 定义:Mybatis是一个支持普通SQL查询、存储过程和高级映射的持久层框架。 途径:MyBatis通过XML文件或者注解的形式配置映射,实现数据库查询。 特性:动态SQL语句。 文件结构:Mybat...

霍淇滨
昨天
2
0
开发技术瓶颈期,如何突破

前言 读书、学习的那些事情,以前我也陆续叨叨了不少,但总觉得 “学习方法” 就是一个永远在路上的话题。个人的能力、经验积累与习惯方法不尽相同,而且一篇文章甚至一本书都很难将学习方法...

_小迷糊
昨天
1
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部