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

  编程也许真的是个技术活,每次你被概念搞的蒙头转向,无从下手的时候你也许会这么想.但这也就是一会会的事,如果你在晚上喝着茶,咬着牙,僵硬着脖子,一页一页的点百度,然后在笔记上一句话一句话的记下你看到的每一篇文章中看懂了的那一句,我想很快那一句一句的积累会把你带到一个恍然大悟的时刻.这点请你务必相信.但前提是,你翻了十多页的百度看到的相关文章大部分是不重复的.......

  总结:上面一段话说了两件事,1柳暗花明是确定是可以常常有的,2百度是确定让人很恼火的.

  再总结:上面都是废话,下面开始干货.

  让我们先扔下Yii的事件,开始捋一捋思路,假设你自己再写自己的框架,现在想给一个类加一个事件处理程序,你该怎么做?多加个方法?No~,如果其他很多类也都用这个方法,你每个类都写一遍吗?继承?No~,那么多类都继承自一个写有你要的方法的父类?你每个类去改吗?如果别的类本来就有父类呢?require?好聪明,不管程序逻辑判断的结果,先加载进来再说,简单是简单了,可是很笨对吗?所以,还是No.如果当你程序逻辑判断需要一个处理方法的时候,再把这个方法引进来运行一下,不需要的时候就不管,其他任何地方也都可以调用这个方法,那多好是不是?Yii解决这个问题的方式就是事件.

  事件应该是个动作吧?点击事件--你很快就能想到这个词,这是js里的,那Yii的事件和这个是不是一样呢?我们结合来看看.首先,js里点击要有个发起的动作吧,那Yii的点击最少也要有个代码段来表示这触发了个动作吧,这是第一.js点击后总要有个处理程序吧?Yii的事件也要有,这是二.除此而外,Yii的事件是为了方便的复用,那总的有个程序段把处理程序和发起类联系到一起吧,这个俗名叫绑定.绑定->触发->处理,很简单是不是?别且,当你昏头专向的时候常常会脱离这个线索的,我们现在要做的是紧紧抓住这根线往下捋.

  绑定在Yii中怎么做的呢?先做两个简单的类,A类中有我们想要的处理程序,我们想把他绑定到B类上去

  

   class A {}

  class B{

    function showChange(){
        echo ‘changed me‘;
      }   }

  现在A什么都没有,怎么调用B呢?我们在这里假设了一个设定宽度的事件,用Yii的魔术方法来发起动作.

  

class A{  public $width;

   public function setWidth($width){
      if($this->hasEventHandler(‘onChange‘)){
          $this->raiseEvent(‘onChange‘, $event);
      }
      $this->width = $width;
   }
}    

  请注意,setWidth是Yii的魔术方法,当你设定A类的width属性时候会自动调用的.$this->raiseEvent(‘onChange‘, $event);这一句就是核心,当你设定A类的width属性时候,这句话就会去调用一个名叫onChange的方法链,如果这个链上有程序,就会依次执行的.那这个名叫onChange的方法链和上面的B类中的showChange有什么关系呢,只要一个句话就可以把showChange赋给onChange,$j->onChange=array($s,‘showChange‘);,具体是这样的

 

   $j=new A;

  $s=new B;

  $j->onChange=array($s,‘showChange‘);

  就这样,把B类的showChange方法绑定到了A类的onChange方法链上去了,绑定完了.绑定完了怎么触发呢?出发很简单啊,setWidth是Yii魔术方法啊,只要width有变化就会出发这个方法,然后,raiseEvent就会去找onChange上的所有绑定了的程序,然后挨个执行吗.

  

    $j->width=250;

  现在看懂了没有?我们来总结一下,

  $j->onChange=array($s,‘showChange‘);是绑定  $this->raiseEvent(‘onChange‘, $event); 是触发  function showChange{} 是执行的程序   如果上面没看懂?建议再看几遍,看到看懂为止,因为下来就要来点花哨的了,还是一样的,上面是按着绑定->触发->执行的条理捋下来的,下面呢就要按上面的内容捋下来,稍微扩展下.我拿一个网上的例子讲,但是他讲的真心没我讲的好懂  第一步先新建一个类,别被类名字唬住,望文生义,就当它是个普通类  
class NewCommentEvent extends CModelEvent {
    public $comment;
    public $post;
}

  再建立一个model类,数据来源  

class Post extends CActiveRecord {

    function addComment(Comment $comment){
        $comment->post_id = $this->id;

        $event = new NewCommentEvent($this);
        $event->post = $this;
        $event->comment = $comment;

        $this->onNewComment($event);
        return $event->isValid;
    }

    public function onNewComment($event) {

        $this->raiseEvent(‘onNewComment‘, $event);
    }
}

  下来是处理程序类,就像上一个例子里的B类  

class Notifier {
    function comment($event){
        $text = "There was new comment from {$event->comment->author} on post {$event->post->title}";
        mail(‘[email protected]‘, ‘New comment‘, $text);
    }
}

  最后还有个类,嗯,类多了点,大概是为了模拟Yii里的真实环境吧,这个类才是主控类

class PostController extends CController
{
    function actionAddComment()
    {
        $post = Post::model()->findByPk(10);
        $notifier = new Notifier();

        $post->onNewComment = array($notifier, ‘comment‘);

            $comment = new Comment();
            $comment->author = ‘Sam Dark‘;
            $comment->text = ‘Yii events are amazing!‘;

            $post->addComment($comment);
    }
}

  好了,我们从这个主控类PostController开始捋,首先它获取了数据,然后把处理程序类 $notifier实例化了,这个类里有我们要的事件处理程序,然后它把数据来源post类里的onNewComment方法链上挂上了事件处理程序,最后调用了post的addComment方法,传入了一个新的类,名字叫Comment,这段代码没问题了,只有不知道addComment是要干嘛?我们进入到post类里看

  post类里的addComment,首先接收了Comment的实例,把这个实例又传给了NewCommentEvent里的Comment属性,然后post把自己也传给了NewCommentEvent里的post属性,然后调用了自己的onNewComment方法

 $event = new NewCommentEvent($this);
        $event->post = $this;
        $event->comment = $comment;

        $this->onNewComment($event);

  自己的onNewCOmment方法就一句话,里面放了一个触发程序 $this->raiseEvent(‘onNewComment‘, $event);这句话要是放在addComment里,替换掉$this->onNewComment($event);也是完全可以的;

  这里就出现了事件里最最容易被忽视然后被忽悠,然后就晕掉了的点,$this->onNewComment($event)中的onNewComment和$this->raiseEvent(‘onNewComment‘, $event)中的onNewCOmment可是两个东西哦!$this->onNewComment($event)中的onNewComment是一个方法,这个方法在post中定义了,而$this->raiseEvent(‘onNewComment‘, $event)中的onNewComment是一个方法链名称;这个方法链上现在绑定是class Notifier中的 comment方法,这个绑定是在主控类的PostController 中 actionAddComment()中做的.

$post->onNewComment = array($notifier, ‘comment‘);

  那你要是问为什么onNewComment方法链的这个变量为什么没有见在定义啊,这还是魔术方法_set的效果吗.我把它称为方法链是为了让大家从概念上更好区分一些,其实它就是个变量,里面存储了你绑定的各个处理程序名字,方便以后调用.

  另外, raiseEvent(‘onNewComment‘, $event)中的$event是一个类实例,这里的作用是向onNewComment传递参数,这个参数最后被comment方法调用了,其实还可以穿CEvent类及其子类的实例进去,类似于

 $j->onChange(new CEvent($this, array(‘statime‘ => $statime, ‘endtime‘ => $endtime)));//或者 $j->onChange(new CEvent($this));

  到这里为止,事件的过程已经捋完了,至于在哪里绑定,在哪里触发,你可以分开来写,也可以一股脑的塞到一个类里,只要做完整这三步就没问题了,现在是不是有点懂了?那赶紧转回去再看一遍啊,懂了这些后,至于行为那就不是问题了,如果有很多类似的处理程序可以放在一个类里,继承自CBehavior,然后你在要用的时候就直接attachBehavior()就可以了,具体参数看看API就知道了,行为就是事件的升级版,可以传多个方法,还可以传属性,一次性传入了一个类,那可以做的东西就多了是吧?

 

  

  

时间: 2024-08-01 10:44:19

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

C#事件的理解以及自定义事件的方法

事件的理解: 在skyline项目的开发中,遇到了一个新的知识:事件. 在程序中,我希望实现一个功能,当视点坐标移动的时候可以实时的得到视点的坐标.这里就需要使用事件这个概念:当坐标发生移动,则触发了一个特定的事件,他可以发出一个信号,而用户可以自定义一个函数(参数必须与事件委托的参数相同,这个后面解释),当他发出一个信号,我就可以执行这个函数. 比方说:甲和乙是朋友,上午见面了,乙和甲说,今天中午吃完饭叫我一声,我带你去网吧玩. 在这个情景中,甲吃饭这件事情是乙没有办法控制的.他只可以等甲吃完

使用委托中介租房理解委托与事件

委托和事件,.Net Framework中的应用非常广泛,然而,较好的理解委托和事件对很多接触C#时间不长的人来说并不容易.它们就像一道门槛儿,跨过去的,觉得太容易了,而没有过去的人每次见到委托事件就觉得心慌慌,浑身不自在. 我个人还是比较喜欢用面向对象的编程思想去理解逻辑程序,理解编程.下面就用委托中介公司租房子的示例理解使用委托流程: 1.定义委托和委托对象——租房人想要租房,但是没有房源,于是委托中介找房子:2.编写要委托的方法——租房中介有房源,可以找到房子:3.将要委托的方法传递给委托

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

关于 Yii 的事件和行为的描述,可参考 http://www.yiiframework.com/doc/api/1.1/CComponent 事件 事件模型就是设计模式中的“观察者模式”:当对象的状态发生了变化,那么这个对象可以将该事件通知其它对象. 为了使用事件模型,需要实现这三个步骤:1.定义事件:2.注册事件句柄:3.触发事件. 为什么要做这三个步骤呢?因为对于 PHP 本身,它的执行过程不是以进程化来运行的, 所以 Yii 的事件触发机制不会像 ActionScript 3+ 那样,直

深入理解js Dom事件机制(二)——添加事件处理程序

深入理解js Dom事件机制(一)--事件流 事件就是当用户或者浏览器自身执行的某种动作,诸如 click.mouseover等都是事件的名称,那响应个事件的函数就称为事件处理程序(事件处理函数.事件句柄). 事件处理程序的名字都是以on+事件名称命名,比如 click事件的事件处理程序就是onclick, 为某个事件指定事件处理程序的方式大致分为三种. 1.HTML事件处理程序 这个很简单,大家基本初学js的时候都应该用过,就不再赘述,直接看实例代码 <!DOCTYPE html> <

C#学习之初步理解委托、事件、匿名方法和Lambda

最经在学习LinqtoSql,然后扯到Lambda表达式,然后扯到匿名方法,然后扯到委托,最后扯到事件处理...后来发现对委托这个概念和事件处理这个过程理解得不是很清晰,遂得一下学习笔记.那里说得不对,请大家多多指教! 第一部分:理解委托 委托委托,顾名思义,就是类似于中间人的意思,有些事情你不做,委托别人去做,比如你想相亲,但你不想去主动约女孩子,那你可以交给媒婆去帮你约. 如果你学过C++,请把委托理解成函数指针,都是为了调用函数.函数指针可以调用符合该函数指针要求的函数.什么叫符合该函数指

通过一个WPF实例进一步理解委托和事件

在前写过"浅谈C#中的委托"和"浅谈C#中的事件"两篇博客,内容有些抽象,似乎难以说明委托和事件的关系. 今天通过一个小程序来进一步说明二者的使用及联系. 首先新建一个WPF应用程序,取名TestDelegateAndEvent. 在.xmal中加入四个按钮,并添加Window_Loaded事件. 代码如下: <Window x:Class="TestDelegateAndEvent.MainWindow" xmlns="http

【译】理解node.js事件轮询

Node.js的第一个基本论点是I/O开销很大. 当前编程技术中等待I/O完成会浪费大量的时间.有几种方法可以处理这种性能上的影响: 同步:每次处理一个请求,依次处理.优点:简单:缺点:任何一个请求都可以阻塞所有其他的请求. Fork一个新进程:开一个新进程来处理每个请求.优点:容易:缺点:不能很好的扩展,成百上千个连接意味着成百上千个进程.fork()函数相当于Unix程序员的锤子,因为它很有用,每个问题看起来就像一个钉子,通常会被过度使用.(译者注:直译比较拗口,我理解的意思是,Unix程序

一个demo让你彻底理解Android触摸事件的并发

注:本文涉及的demo的地址:https://github.com/absfree/TouchDispatch 1. 触摸动作及事件序列 (1)触摸事件的动作 触摸动作一共有三种:ACTION_DOWN.ACTION_MOVE.ACTION_UP.当用户手指接触屏幕时,便产生一个动作为ACTION_DOWN的触摸事件,此时若用户的手指立即离开屏幕,会产生一个动作为ACTION_UP的触摸事件:若用户手指接触屏幕后继续滑动,当滑动距离超过了系统中预定义的距离常数,则产生一个动作为ACTION_MO

深入理解 View 的事件传递机制

引言:现在 GitHub 上酷炫的 Android 控件越来越多,一方面我们可以让 App 各美观,另一方面我们这些开发者也可以从中学习到各种知识.写下这篇博文主要是记录研究自定义控件源码过程中接触到的知识盲区,帮助自己巩固知识的同时,也和大家交流学习,一起进步. Demo源码 废话不多说,进入正题: 一.概述 View 事件传递机制 用户通过点击.滑动屏幕与 App 产生交互是移动互联网时代的交互基础,那么在 Android 中,用户的点击.滑动是怎么和 Android 系统产生交互的呢? 在