清晰理解Yii的事件和行为

转载 2016年08月29日 09:16:16

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

  总结:上面一段话说了两件事,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('admin@example.com', '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就知道了,行为就是事件的升级版,可以传多个方法,还可以传属性,一次性传入了一个类,那可以做的东西就多了是吧?


转自:http://www.cnblogs.com/phpinfo/p/4004673.html

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

个人觉得,在 Yii 里面,最难以明白的就是事件(Event)和行为(behavior)了。这不仅仅是因为它们的概念 比较难明,关键是它们的应用场景比较难明,不知道什么时候应该使用事件和行为来开...

Yii框架中行为Behavior的概念

使用行为(behavior)可以在不修改现有类的情况下,对类的功能进行扩充。通过将行为绑定到一个类,可以使类具有行为本身所定义的属性和方法,就好像类本来就有这些属性和方法一样。...

YII中的CComponent,CEvent与Behavior示例

YII中的CComponent,CEvent与Behavior及CActiveRecordBehavior 完成如下功能,一个JTool类,继承CComponent,当其长度改变时,调用事件,输出"...

深入理解 Yii2.0 - 属性,事件,行为。

前言本博客基于 深入理解Yii2.0.并且参考Yii2.0 官方文档,加上自己使用Yii2.0的一些总结和理解。Yii 2.0Yii 是一个高性能,基于组件的 PHP 框架。 为什么要用Yii 2....

yii2框架-yii2的事件(五)

yii2中使用事件,可以在特定的时间点,触发执行预先设定的一段代码,事件既是代码解耦的一种方式,也是设计业务流程的一种模式。现代软件中,事件无处不在,比如,你发了个微博,触发了一个事件,导致关注你的人...

Yii2学习笔记(九):行为Behavior的使用

行为就是继承yii\base\behavior,可以绑定到任意yii\base\compent实例上,然后这个compent实例就拥有了行为类所具有的属性和方法; 注意:Behavior只能与Com...

[事件] -- yii2事件使用

yii2中使用事件,可以在特定的时间点,触发执行预先设定的一段代码,事件既是代码解耦的一种方式,也是设计业务流程的一种模式。现代软件中,事件无处不在,比如,你发了个微博,触发了一个事件,导致关注你的人...
  • lmjy102
  • lmjy102
  • 2017年01月05日 11:14
  • 989

给定A, B两个整数,不使用除法和取模运算,求A/B的商和余数

给定A, B两个整数,不使用除法和取模运算,求A/B的商和余数。 1.   最基本的算法是,从小到大遍历: for (i = 2 to A -1)          if (i * B > A)...

配置SOIL库,实现纹理加载

SOIL 是一个用于向OpenGL中加载

SceneManager.LoadScene的使用方法

SceneManager.LoadScene的使用方法
  • XYK0318
  • XYK0318
  • 2016年03月17日 09:52
  • 18572
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:清晰理解Yii的事件和行为
举报原因:
原因补充:

(最多只允许输入30个字)