Yii源码阅读笔记(八)

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

  1 <?php
  2 /**
  3  * @link http://www.yiiframework.com/
  4  * @copyright Copyright (c) 2008 Yii Software LLC
  5  * @license http://www.yiiframework.com/license/
  6  */
  7
  8 namespace yii\base;
  9
 10 /**
 11  * Event is the base class for all event classes.
 12  * Event 是所有事件类的基类,是对Component的深化
 13  *
 14  * It encapsulates the parameters associated with an event.
 15  * The [[sender]] property describes who raises the event.
 16  * And the [[handled]] property indicates if the event is handled.
 17  * If an event handler sets [[handled]] to be true, the rest of the
 18  * uninvoked handlers will no longer be called to handle the event.
 19  *
 20  * Additionally, when attaching an event handler, extra data may be passed
 21  * and be available via the [[data]] property when the event handler is invoked.
 22  *
 23  * @author Qiang Xue <[email protected]>
 24  * @since 2.0
 25  */
 26 class Event extends Object
 27 {
 28     /**
 29      * @var string the event name. This property is set by [[Component::trigger()]] and [[trigger()]].
 30      * Event handlers may use this property to check what event it is handling.
 31      * 事件的名字,通过[[Component::trigger()]] 和 [[trigger()]]方法设置,事件处理程序通过这个属性类检查处理的事件
 32      */
 33     public $name;
 34     /**
 35      * @var object the sender of this event. If not set, this property will be
 36      * set as the object whose "trigger()" method is called.
 37      * This property may also be a `null` when this event is a
 38      * class-level event which is triggered in a static context.
 39      *
 40      * 触发事件的对象,如果未设置,则设置为调用"trigger()"方法的对象,如果是在静态环境下触发的类级别的事件,怎为空
 41      */
 42     public $sender;
 43     /**
 44      * @var boolean whether the event is handled. Defaults to false.
 45      * When a handler sets this to be true, the event processing will stop and
 46      * ignore the rest of the uninvoked event handlers.
 47      *
 48      * 记录事件是否已被处理,当 handled 被设置为 true 时,执行到这个 event 的时候,会停止,并忽略剩下的 event
 49      */
 50     public $handled = false;
 51     /**
 52      * @var mixed the data that is passed to [[Component::on()]] when attaching an event handler.
 53      * Note that this varies according to which event handler is currently executing.
 54      * 事件加载时传入的数据,对应当前执行的事件处理程序
 55      */
 56     public $data;
 57
 58     /**
 59      * @var array contains all globally registered event handlers.
 60      * 存储所有的 event,因为是 static 的属性,所有的 event 对象/类都共享这一份数据
 61      */
 62     private static $_events = [];
 63
 64
 65     /**
 66      * Attaches an event handler to a class-level event.
 67      * 为一个类添加事件
 68      *
 69      * When a class-level event is triggered, event handlers attached
 70      * to that class and all parent classes will be invoked.
 71      *
 72      * For example, the following code attaches an event handler to `ActiveRecord`‘s
 73      * `afterInsert` event:
 74      *
 75      * ```php
 76      * Event::on(ActiveRecord::className(), ActiveRecord::EVENT_AFTER_INSERT, function ($event) {
 77      *     Yii::trace(get_class($event->sender) . ‘ is inserted.‘);
 78      * });
 79      * ```
 80      *
 81      * The handler will be invoked for EVERY successful ActiveRecord insertion.
 82      *
 83      * For more details about how to declare an event handler, please refer to [[Component::on()]].
 84      *
 85      * @param string|object $class 定义的类级别的对象或者类名称.
 86      * @param string $name 事件名
 87      * @param callable $handler 事件处理程序.
 88      * @param mixed $data 数据.
 89      * When the event handler is invoked, this data can be accessed via [[Event::data]].
 90      * @param boolean $append whether to append new event handler to the end of the existing
 91      * handler list. If false, the new handler will be inserted at the beginning of the existing
 92      * handler list.
 93      * @see off()
 94      */
 95     public static function on($class, $name, $handler, $data = null, $append = true)
 96     {
 97          // 去掉 class 最左边的斜线
 98         $class = ltrim($class, ‘\\‘);
 99         if ($append || empty(self::$_events[$name][$class])) {
100             // 如果 append 为true,就放到 $_events 中名字为 $name 的数组的最后
101             self::$_events[$name][$class][] = [$handler, $data];
102         } else {
103             //否则放到最前面
104             array_unshift(self::$_events[$name][$class], [$handler, $data]);
105         }
106     }
107
108     /**
109      * Detaches an event handler from a class-level event.
110      * [[on()]]方法的反方法,移除一个类的事件
111      * This method is the opposite of [[on()]].
112      *
113      * @param string|object $class 定义的类级别的对象或者类名称.
114      * @param string $name 事件名
115      * @param callable $handler 事件处理程序.
116      * If it is null, all handlers attached to the named event will be removed.
117      * @return boolean whether a handler is found and detached.
118      * @see on()
119      */
120     public static function off($class, $name, $handler = null)
121     {
122         // 去掉 class 最左边的斜线
123         $class = ltrim($class, ‘\\‘);
124         if (empty(self::$_events[$name][$class])) {
125             // 如果不存在该事件,返回false
126             return false;
127         }
128         if ($handler === null) {
129             // 如果 handler 为空,也就是没有规定移除的事件处理程序,直接将该事件移除,即移出所有的是这个名字的事件
130             unset(self::$_events[$name][$class]);
131             return true;
132         } else {
133             $removed = false; //移除标记
134             // 如果 $handler 不为空,遍历 $_events 找到相应的 handler,只移除这个 handler 和 data 组成的数组
135             foreach (self::$_events[$name][$class] as $i => $event) {
136                 if ($event[0] === $handler) {
137                     unset(self::$_events[$name][$class][$i]);
138                     $removed = true;
139                 }
140             }
141             if ($removed) {
142                 //如果删除成功,调用array_values方法重新赋值,初始化索引
143                 self::$_events[$name][$class] = array_values(self::$_events[$name][$class]);
144             }
145
146             return $removed;
147         }
148     }
149
150     /**
151      * Returns a value indicating whether there is any handler attached to the specified class-level event.
152      * Note that this method will also check all parent classes to see if there is any handler attached
153      * to the named event.
154      * 检测在某个类或者对象是否具有某个事件/会同时检测父类
155      *
156      * @param string|object $class 定义的类级别的对象或者类名称.
157      * @param string $name 事件名
158      * @return boolean whether there is any handler attached to the event.
159      */
160     public static function hasHandlers($class, $name)
161     {
162         if (empty(self::$_events[$name])) {
163              //如果不存在,直接返回false
164             return false;
165         }
166         if (is_object($class)) {
167             // 如果是一个 object,就获取其类名  get_class 内置函数,用于获取对象的方法
168             $class = get_class($class);
169         } else {
170              // 如果是一个类名,就去掉 class 最左边的斜杠
171             $class = ltrim($class, ‘\\‘);
172         }
173         //将该类/该对象对应的类的父类以及该类/该对象对应的类实现的接口名称合并到一个数组中
174         $classes = array_merge(
175             [$class],
176             class_parents($class, true),//获取父类的类名
177             class_implements($class, true)//获取当前类和父类实现的所有接口类名
178         );
179         //判断是否存在事件处理程序,存在返回true
180         foreach ($classes as $class) {
181             if (!empty(self::$_events[$name][$class])) {
182                 return true;
183             }
184         }
185
186         return false;
187     }
188
189     /**
190      * Triggers a class-level event.
191      * This method will cause invocation of event handlers that are attached to the named event
192      * for the specified class and all its parent classes.
193      * 触发某个类或者对象的某个事件/会同时作用于父类
194      *
195      * @param string|object $class 定义的类级别的对象或者类名称.
196      * @param string $name 事件名
197      * @param Event $event the event parameter. If not set, a default [[Event]] object will be created.
198      */
199     public static function trigger($class, $name, $event = null)
200     {
201         if (empty(self::$_events[$name])) {
202             //如果事件不存在,直接返回
203             return;
204         }
205         if ($event === null) {
206              // 构建Event对象,为传入到handler函数中做准备
207             $event = new static;
208         }
209         $event->handled = false;//事件是否被处理标志
210         $event->name = $name;//事件名
211
212         if (is_object($class)) {
213             if ($event->sender === null) {
214                 // 如果 $class 是个对象,并且是 sender 为空,就将 $class 赋给 sender,即 $class 就是触发事件的对象
215                 $event->sender = $class;
216             }
217             $class = get_class($class);//取得类名称
218         } else {
219             $class = ltrim($class, ‘\\‘);//去掉类名称左边的斜线
220         }
221         //将该类/该对象对应的类的父类以及该类/该对象对应的类实现的接口名称合并到一个数组中
222         $classes = array_merge(
223             [$class],
224             class_parents($class, true),
225             class_implements($class, true)
226         );
227
228         foreach ($classes as $class) {//遍历所有的类
229             if (!empty(self::$_events[$name][$class])) {//找到符合条件的类
230                 foreach (self::$_events[$name][$class] as $handler) {
231                     $event->data = $handler[1];//设置data数据
232                     call_user_func($handler[0], $event);//调用处理程序
233                     if ($event->handled) {//事件是否被处理标志为真,结束执行
234                         return;
235                     }
236                 }
237             }
238         }
239     }
240 }
时间: 2024-12-09 22:46:53

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

Yii源码阅读笔记 - 日志组件

?使用 Yii框架为开发者提供两个静态方法进行日志记录: Yii::log($message, $level, $category);Yii::trace($message, $category); 两者的区别在于后者依赖于应用开启调试模式,即定义常量YII_DEBUG: defined('YII_DEBUG') or define('YII_DEBUG', true); Yii::log方法的调用需要指定message的level和category.category是格式为“xxx.yyy.z

Yii源码阅读笔记(一)

今天开始阅读yii2的源码,想深入了解一下yii框架的工作原理,同时学习一下优秀的编码规范和风格.在此记录一下阅读中的小心得. 每个框架都有一个入口文件,首先从入口文件开始,yii2的入口文件位于web目录的index.php,用于启动web应用和配置一些路径参数. index.php—— 1 // comment out the following two lines when deployed to production 2 defined('YII_DEBUG') or define('Y

Yii源码阅读笔记(十八)

View中的查找视图文件方法和渲染文件方法 1 /** 2 * Finds the view file based on the given view name. 3 * 通过view文件名查找view文件 4 * @param string $view the view name or the path alias of the view file. Please refer to [[render()]] 5 * on how to specify this parameter. 6 * @

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

Yii/web中的Controller类,实现参数绑定,启动csrf验证功能,重定向页面功能: 1 namespace yii\web; 2 3 use Yii; 4 use yii\base\InlineAction; 5 use yii\helpers\Url; 6 7 /** 8 * Controller is the base class of web controllers. 9 * 10 * @author Qiang Xue <[email protected]> 11 * @s

Yii源码阅读笔记(二)

接下来阅读BaseYii.php vendor/yiisoft/yii2/Yii.php—— 1 namespace yii; 2 3 use yii\base\InvalidConfigException; 4 use yii\base\InvalidParamException; 5 use yii\base\UnknownClassException; 6 use yii\log\Logger; 7 use yii\di\Container; 第1行定义命名空间为yii: 第3到7行使用了

Yii源码阅读笔记(三)

接着上次的继续阅读BaseYii.php vendor/yiisoft/yii2/BaseYii.php—— 1 public static function getRootAlias($alias)//获取根别名 2 { //查找别名中斜线的位置 3 $pos = strpos($alias, '/'); //根据斜线的结果判断,如果不包含斜线,表示输入为根别名,否则截取斜线前面的部分作为根别名 4 $root = $pos === false ? $alias : substr($alias

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

ServiceLocator,服务定位类,用于yii2中的依赖注入,通过以ID为索引的方式缓存服务或则组件的实例来定位服务或者组件: 1 namespace yii\di; 2 3 use Yii; 4 use Closure; 5 use yii\base\Component; 6 use yii\base\InvalidConfigException; 7 8 /** 9 * ServiceLocator implements a [service locator](http://en.wi

Yii源码阅读笔记(二十一)——请求处理流程

Yii2请求处理流程: 首先:项目路径/web/index.php (new yii\web\Application($config))->run();//根据配置文件创建App实例,先实例化yii\web\Application(),然后调用run()方法 该语句可分为两步: $application = new yii\web\Application($config);//实例化app $application->run();//调用run()方法 $config 为配置文件,通过 req

Yii源码阅读笔记(二十六)

Application 类中设置路径的方法和调用ServiceLocator(服务定位器)加载运行时的组件的方法注释: 1 /** 2 * Handles the specified request. 3 * 处理指定的请求--抽象方法 4 * This method should return an instance of [[Response]] or its child class 5 * which represents the handling result of the reques