前面阅读了Yii2的两个基本类Object和Component,了解了Yii的三个重要概念属性、事件、行为,下面开始阅读Event类,Event类是所有事件类的基类:

 <?php
 /**
  * @link http://www.yiiframework.com/
  * @copyright Copyright (c) 2008 Yii Software LLC
  * @license http://www.yiiframework.com/license/
  */

 namespace yii\base;

 /**
  * Event is the base class for all event classes.
  * Event 是所有事件类的基类,是对Component的深化
  *
  * It encapsulates the parameters associated with an event.
  * The [[sender]] property describes who raises the event.
  * And the [[handled]] property indicates if the event is handled.
  * If an event handler sets [[handled]] to be true, the rest of the
  * uninvoked handlers will no longer be called to handle the event.
  *
  * Additionally, when attaching an event handler, extra data may be passed
  * and be available via the [[data]] property when the event handler is invoked.
  *
  * @author Qiang Xue <qiang.xue@gmail.com>
  * @since 2.0
  */
 class Event extends Object
 {
     /**
      * @var string the event name. This property is set by [[Component::trigger()]] and [[trigger()]].
      * Event handlers may use this property to check what event it is handling.
      * 事件的名字,通过[[Component::trigger()]] 和 [[trigger()]]方法设置,事件处理程序通过这个属性类检查处理的事件
      */
     public $name;
     /**
      * @var object the sender of this event. If not set, this property will be
      * set as the object whose "trigger()" method is called.
      * This property may also be a `null` when this event is a
      * class-level event which is triggered in a static context.
      *
      * 触发事件的对象,如果未设置,则设置为调用"trigger()"方法的对象,如果是在静态环境下触发的类级别的事件,怎为空
      */
     public $sender;
     /**
      * @var boolean whether the event is handled. Defaults to false.
      * When a handler sets this to be true, the event processing will stop and
      * ignore the rest of the uninvoked event handlers.
      *
      * 记录事件是否已被处理,当 handled 被设置为 true 时,执行到这个 event 的时候,会停止,并忽略剩下的 event
      */
     public $handled = false;
     /**
      * @var mixed the data that is passed to [[Component::on()]] when attaching an event handler.
      * Note that this varies according to which event handler is currently executing.
      * 事件加载时传入的数据,对应当前执行的事件处理程序
      */
     public $data;

     /**
      * @var array contains all globally registered event handlers.
      * 存储所有的 event,因为是 static 的属性,所有的 event 对象/类都共享这一份数据
      */
     private static $_events = [];

     /**
      * Attaches an event handler to a class-level event.
      * 为一个类添加事件
      *
      * When a class-level event is triggered, event handlers attached
      * to that class and all parent classes will be invoked.
      *
      * For example, the following code attaches an event handler to `ActiveRecord`'s
      * `afterInsert` event:
      *
      * ```php
      * Event::on(ActiveRecord::className(), ActiveRecord::EVENT_AFTER_INSERT, function ($event) {
      *     Yii::trace(get_class($event->sender) . ' is inserted.');
      * });
      * ```
      *
      * The handler will be invoked for EVERY successful ActiveRecord insertion.
      *
      * For more details about how to declare an event handler, please refer to [[Component::on()]].
      *
      * @param string|object $class 定义的类级别的对象或者类名称.
      * @param string $name 事件名
      * @param callable $handler 事件处理程序.
      * @param mixed $data 数据.
      * When the event handler is invoked, this data can be accessed via [[Event::data]].
      * @param boolean $append whether to append new event handler to the end of the existing
      * handler list. If false, the new handler will be inserted at the beginning of the existing
      * handler list.
      * @see off()
      */
     public static function on($class, $name, $handler, $data = null, $append = true)
     {
          // 去掉 class 最左边的斜线
         $class = ltrim($class, '\\');
         if ($append || empty(self::$_events[$name][$class])) {
             // 如果 append 为true,就放到 $_events 中名字为 $name 的数组的最后
             self::$_events[$name][$class][] = [$handler, $data];
         } else {
             //否则放到最前面
             array_unshift(self::$_events[$name][$class], [$handler, $data]);
         }
     }

     /**
      * Detaches an event handler from a class-level event.
      * [[on()]]方法的反方法,移除一个类的事件
      * This method is the opposite of [[on()]].
      *
      * @param string|object $class 定义的类级别的对象或者类名称.
      * @param string $name 事件名
      * @param callable $handler 事件处理程序.
      * If it is null, all handlers attached to the named event will be removed.
      * @return boolean whether a handler is found and detached.
      * @see on()
      */
     public static function off($class, $name, $handler = null)
     {
         // 去掉 class 最左边的斜线
         $class = ltrim($class, '\\');
         if (empty(self::$_events[$name][$class])) {
             // 如果不存在该事件,返回false
             return false;
         }
         if ($handler === null) {
             // 如果 handler 为空,也就是没有规定移除的事件处理程序,直接将该事件移除,即移出所有的是这个名字的事件
             unset(self::$_events[$name][$class]);
             return true;
         } else {
             $removed = false; //移除标记
             // 如果 $handler 不为空,遍历 $_events 找到相应的 handler,只移除这个 handler 和 data 组成的数组
             foreach (self::$_events[$name][$class] as $i => $event) {
                 if ($event[0] === $handler) {
                     unset(self::$_events[$name][$class][$i]);
                     $removed = true;
                 }
             }
             if ($removed) {
                 //如果删除成功,调用array_values方法重新赋值,初始化索引
                 self::$_events[$name][$class] = array_values(self::$_events[$name][$class]);
             }

             return $removed;
         }
     }

     /**
      * Returns a value indicating whether there is any handler attached to the specified class-level event.
      * Note that this method will also check all parent classes to see if there is any handler attached
      * to the named event.
      * 检测在某个类或者对象是否具有某个事件/会同时检测父类
      *
      * @param string|object $class 定义的类级别的对象或者类名称.
      * @param string $name 事件名
      * @return boolean whether there is any handler attached to the event.
      */
     public static function hasHandlers($class, $name)
     {
         if (empty(self::$_events[$name])) {
              //如果不存在,直接返回false
             return false;
         }
         if (is_object($class)) {
             // 如果是一个 object,就获取其类名  get_class 内置函数,用于获取对象的方法
             $class = get_class($class);
         } else {
              // 如果是一个类名,就去掉 class 最左边的斜杠
             $class = ltrim($class, '\\');
         }
         //将该类/该对象对应的类的父类以及该类/该对象对应的类实现的接口名称合并到一个数组中
         $classes = array_merge(
             [$class],
             class_parents($class, true),//获取父类的类名
             class_implements($class, true)//获取当前类和父类实现的所有接口类名
         );
         //判断是否存在事件处理程序,存在返回true
         foreach ($classes as $class) {
             if (!empty(self::$_events[$name][$class])) {
                 return true;
             }
         }

         return false;
     }

     /**
      * Triggers a class-level event.
      * This method will cause invocation of event handlers that are attached to the named event
      * for the specified class and all its parent classes.
      * 触发某个类或者对象的某个事件/会同时作用于父类
      *
      * @param string|object $class 定义的类级别的对象或者类名称.
      * @param string $name 事件名
      * @param Event $event the event parameter. If not set, a default [[Event]] object will be created.
      */
     public static function trigger($class, $name, $event = null)
     {
         if (empty(self::$_events[$name])) {
             //如果事件不存在,直接返回
             return;
         }
         if ($event === null) {
              // 构建Event对象,为传入到handler函数中做准备
             $event = new static;
         }
         $event->handled = false;//事件是否被处理标志
         $event->name = $name;//事件名

         if (is_object($class)) {
             if ($event->sender === null) {
                 // 如果 $class 是个对象,并且是 sender 为空,就将 $class 赋给 sender,即 $class 就是触发事件的对象
                 $event->sender = $class;
             }
             $class = get_class($class);//取得类名称
         } else {
             $class = ltrim($class, '\\');//去掉类名称左边的斜线
         }
         //将该类/该对象对应的类的父类以及该类/该对象对应的类实现的接口名称合并到一个数组中
         $classes = array_merge(
             [$class],
             class_parents($class, true),
             class_implements($class, true)
         );

         foreach ($classes as $class) {//遍历所有的类
             if (!empty(self::$_events[$name][$class])) {//找到符合条件的类
                 foreach (self::$_events[$name][$class] as $handler) {
                     $event->data = $handler[1];//设置data数据
                     call_user_func($handler[0], $event);//调用处理程序
                     if ($event->handled) {//事件是否被处理标志为真,结束执行
                         return;
                     }
                 }
             }
         }
     }
 }

Yii源码阅读笔记(八)的更多相关文章

  1. Yii源码阅读笔记(一)

    今天开始阅读yii2的源码,想深入了解一下yii框架的工作原理,同时学习一下优秀的编码规范和风格.在此记录一下阅读中的小心得. 每个框架都有一个入口文件,首先从入口文件开始,yii2的入口文件位于we ...

  2. Yii源码阅读笔记(二十八)

    Yii/web中的Controller类,实现参数绑定,启动csrf验证功能,重定向页面功能: namespace yii\web; use Yii; use yii\base\InlineActio ...

  3. Yii源码阅读笔记(十八)

    View中的查找视图文件方法和渲染文件方法 /** * Finds the view file based on the given view name. * 通过view文件名查找view文件 * ...

  4. Yii源码阅读笔记(三)

    接着上次的继续阅读BaseYii.php vendor/yiisoft/yii2/BaseYii.php—— public static function getRootAlias($alias)// ...

  5. Yii源码阅读笔记(二)

    接下来阅读BaseYii.php vendor/yiisoft/yii2/BaseYii.php—— namespace yii; use yii\base\InvalidConfigExceptio ...

  6. Yii源码阅读笔记(三十五)

    Container,用于动态地创建.注入依赖单元,映射依赖关系等功能,减少了许多代码量,降低代码耦合程度,提高项目的可维护性. namespace yii\di; use ReflectionClas ...

  7. Yii源码阅读笔记(三十四)

    Instance类, 表示依赖注入容器或服务定位器中对某一个对象的引用 namespace yii\di; use Yii; use yii\base\InvalidConfigException; ...

  8. Yii源码阅读笔记(三十三)

    ServiceLocator,服务定位类,用于yii2中的依赖注入,通过以ID为索引的方式缓存服务或则组件的实例来定位服务或者组件: namespace yii\di; use Yii; use Cl ...

  9. Yii源码阅读笔记(三十二)

    web/Application类的注释,继承base/Application类,针对web应用的一些处理: namespace yii\web; use Yii; use yii\base\Inval ...

随机推荐

  1. MySQL常用简单小命令

    1. 登录数据库: mysql -h localhost -u root -p

  2. 网易前端JavaScript编码规范

    在多年开发邮箱webmail过程中,网易邮箱前端团队积累了不少心得体会,我们开发了很多基础js库,实现了大量前端效果组件,开发了成熟的opoa框架以及api组件,在此向大家做一些分享.今天想先和大家聊 ...

  3. wp8 入门到精通 抓包

    抓包工具Fiddler的使用 Fiddler是一款免费且功能强大的数据包抓取软件.它通过代理的方式获取程序http通讯的数据.我们可以利用它来检测网页和服务器的交互情况.下面,我们以http://bl ...

  4. android 页面停几秒后跳转

      <span style="white-space:pre">      </span>//实现等待几秒后跳转,方法一 new Handler().pos ...

  5. loadrunner录制脚本出现urs.asmx解决方法:

    在loadrunner录制过程中可能出现如下脚本: 解决方法: 解决办法:打开IE9的Internet选项-->高级,把设置下面安全中“启用SmartScreen筛选器”不选中,IE默认是选中的 ...

  6. HealthKit开发教程之HealthKit的主要类型数据

    HealthKit开发教程之HealthKit的主要类型数据 在HealthKit中,我们将最常用到的数据称之为主要数据.主要数据基本上有三种:长度类型的数据.质量类型的数据.能量类型的数据.本节将主 ...

  7. mysql之对视图的操作

    1. 为什么要使用视图? 为了提高复杂SQL语句的复用性和表操作的安全性,MySQL数据库管理系统提供了视图特性.所谓视图,本质上是一种虚拟表,在物理上是不存在的,其内容与真实的表相似,包含一系列带有 ...

  8. Real Adaboost总结

    Real Adaboost分类器是对经典Adaboost分类器的扩展和提升,经典Adaboost分类器的每个弱分类器仅输出{1,0}或{+1,-1},分类能力较弱,Real Adaboost的每个弱分 ...

  9. BZOJ2216 : [Poi2011]Lightning Conductor

    $f[i]=\max(a[j]+\lceil\sqrt{|i-j|}\rceil)$, 拆开绝对值,考虑j<i,则决策具有单调性,j>i同理, 所以可以用分治$O(n\log n)$解决. ...

  10. BZOJ2459 : [BeiJing2011]神秘好人

    线段树每个节点维护d[4][4]表示四个顶点之间的最短路,合并时用Floyed合并,查询时分三段然后合并. #include<cstdio> #define N 100010 struct ...