首页 > 代码库 > yii2 源码分析 Component类分析 (二)
yii2 源码分析 Component类分析 (二)
转载请注明链接http://www.cnblogs.com/liuwanqiu/p/6739538.html
组件(component),是Yii框架的基类,实现了属性、事件、行为三类功能,它集成自object类
类前面的大部分注释:
1.事件在定义的类中唯一名称标示,事件名称区分大小写 2.将事件处理程序到附加到事件,是用on 3.有三种事件函数的调用方法,匿名函数调用,对象调用,静态方法调用,全局函数调用 4.可以在配置中配置组件,使用方式是: [ ‘on add‘ => function ($event) { ... } ] 5.当你想在事件中传入数据时可以这样使用: $post->on(‘update‘, function ($event) { // 数据被这样调用 $event->data }, $data); 6.行为类也是该组件类的子类,用法和事件差不多
class Component extends Object { /** * 以键值对的方式存储事件处理 */ private $_events = []; /** *存储对象的行为。默认为null */ private $_behaviors; /** * 返回组件的属性 * 此方法按照下列顺序检查或执行: * * - 属性通过get方法定义,返回get结果 * - 属性是个行为,返回行为的属性值 * * 不要直接调用此方法,因为它是一个PHP魔术方法 */ public function __get($name) { $getter = ‘get‘ . $name; if (method_exists($this, $getter)) { // 判断get方法是否存在,存在就直接返回 return $this->$getter(); } else { //确保行为已经绑定 $this->ensureBehaviors(); foreach ($this->_behaviors as $behavior) { if ($behavior->canGetProperty($name)) { //如果行为中有这个属性,就返回这个属性 return $behavior->$name; } } } //返回人性化的提示,属性只能写或不存在 if (method_exists($this, ‘set‘ . $name)) { throw new InvalidCallException(‘Getting write-only property: ‘ . get_class($this) . ‘::‘ . $name); } else { throw new UnknownPropertyException(‘Getting unknown property: ‘ . get_class($this) . ‘::‘ . $name); } } /** * 设置组件的属性. * 此方法将按下列顺序检查并相应执行: * * - 属性存在,设置该属性并返回 * - 如果 $name 是 ‘on ex‘,就会将 ex 事件添加到该对象中 * - 如果 $name 是 ‘as ex‘,就会将 ex 行为添加到该对象中 * - 添加对 behaviors 的处理,循环 behaviors,如果其中有相应的属性,就设置它 */ public function __set($name, $value) { $setter = ‘set‘ . $name; if (method_exists($this, $setter)) { // 设置该对象的属性,并返回 $this->$setter($value); return; } elseif (strncmp($name, ‘on ‘, 3) === 0) { // 字符串截取后是on开头的,执行on方法附件事件,并返回 $this->on(trim(substr($name, 3)), $value); return; } elseif (strncmp($name, ‘as ‘, 3) === 0) { // 字符串截取后是as开头的,执行attachBehavior方法附件事件,并返回 $name = trim(substr($name, 3)); //$value这个对象是Behavior类的一个实例,取$value为参数,否则静态调用Yii方法创造一个新的对象。并返回 $this->attachBehavior($name, $value instanceof Behavior ? $value : Yii::createObject($value)); return; } else { //确保行为已经绑定 $this->ensureBehaviors(); foreach ($this->_behaviors as $behavior) { if ($behavior->canSetProperty($name)) { //遍历行为,如果行为中有可以设置的属性$name,给该行为类中的属性设置属性值 $behavior->$name = $value; return; } } } //返回人性化的提示,属性只能读或不存在 if (method_exists($this, ‘get‘ . $name)) { throw new InvalidCallException(‘Setting read-only property: ‘ . get_class($this) . ‘::‘ . $name); } else { throw new UnknownPropertyException(‘Setting unknown property: ‘ . get_class($this) . ‘::‘ . $name); } } /** * 检查属性是否已经被定义 * 此方法按照下列顺序检查或执行: * * - 定义过的属性返回真 * - 如果是一个行为,返回行为的属性是否被设置 * - 不存在此属性返回false */ public function __isset($name) { $getter = ‘get‘ . $name; if (method_exists($this, $getter)) { return $this->$getter() !== null; } else { // 确定行为已经绑定 $this->ensureBehaviors(); foreach ($this->_behaviors as $behavior) { if ($behavior->canGetProperty($name)) { // 如果 behavior 中有 $name 属性,且不为 null,该属性存在 返回 true return $behavior->$name !== null; } } } return false; } /** * 设置属性为null,即删除属性 * 重写 Object 中的 unset 方法, * 通过setter定义的属性:设置该属性值为空 * 属性的行为:将属性值设为空 */ public function __unset($name) { $setter = ‘set‘ . $name; if (method_exists($this, $setter)) { $this->$setter(null); return; } else { // 确定行为已经绑定 $this->ensureBehaviors(); foreach ($this->_behaviors as $behavior) { if ($behavior->canSetProperty($name)) { $behavior->$name = null; return; } } } throw new InvalidCallException(‘Unsetting an unknown or read-only property: ‘ . get_class($this) . ‘::‘ . $name); } /** * 调用组件不存在的方法时被隐式调用 * 调用方法名 重写 Object 中的 call 方法,添加对行为的处理,循环 behaviors, * 如果其中有相应方法,就执行该 behavior 的方法 */ public function __call($name, $params) { // 确定行为已经绑定 $this->ensureBehaviors(); foreach ($this->_behaviors as $object) { if ($object->hasMethod($name)) { //行为中存在名为 $name 的方法,就执行它 //call_user_func_array 调用回调函数,并把一个数组参数作为回调函数的参数 return call_user_func_array([$object, $name], $params); } } //方法不存在就抛出异常 throw new UnknownMethodException(‘Calling unknown method: ‘ . get_class($this) . "::$name()"); } /** * 通过克隆现有创建的对象后,此方法会被调用。 * 他将会消除所有的行为。所有的引用属性 仍然会是一个指向原来的变量的引用 */ public function __clone() { $this->_events = []; $this->_behaviors = null; } /** * 返回true或false表示此属性在组件中是否被定义 * - 类拥有一个关联的set或get方法 * (属性名不区分大小写); * - 类具有指定名称的成员变量 (when `$checkVars` is true); * - 附加的行为具有给定名称的属性 (when `$checkBehaviors` is true). */ public function hasProperty($name, $checkVars = true, $checkBehaviors = true) { return $this->canGetProperty($name, $checkVars, $checkBehaviors) || $this->canSetProperty($name, false, $checkBehaviors); } /** * 返回一个值,该值指示是否可以读取属性。 * A property can be read if: * * - 获取属性 * (属性名称不区分大小写); * 其它参数和hasProperty方法的参数差不多,就不一一介绍了。。。 */ public function canGetProperty($name, $checkVars = true, $checkBehaviors = true) { if (method_exists($this, ‘get‘ . $name) || $checkVars && property_exists($this, $name)) { return true; } elseif ($checkBehaviors) { $this->ensureBehaviors(); foreach ($this->_behaviors as $behavior) { if ($behavior->canGetProperty($name, $checkVars)) { return true; } } } return false; } /** * 返回一个方法是否可以被设置 */ public function canSetProperty($name, $checkVars = true, $checkBehaviors = true) { if (method_exists($this, ‘set‘ . $name) || $checkVars && property_exists($this, $name)) { return true; } elseif ($checkBehaviors) { $this->ensureBehaviors(); foreach ($this->_behaviors as $behavior) { if ($behavior->canSetProperty($name, $checkVars)) { return true; } } } return false; } /** * 返回一个布尔值,表示是否有此方法 */ public function hasMethod($name, $checkBehaviors = true) { if (method_exists($this, $name)) { return true; } elseif ($checkBehaviors) { $this->ensureBehaviors(); foreach ($this->_behaviors as $behavior) { if ($behavior->hasMethod($name)) { return true; } } } return false; } /** * 返回该组件应表现为的行为列表. * * 子类可以重写此方法,以指定它们想要表现的行为. * * 此方法的返回值应该是由行为名称索引的行为对象或配置数组,行为配置可以是指定行为类的字符串,也可以是以下结构的数组: * * ```php * ‘behaviorName‘ => [ * ‘class‘ => ‘BehaviorClass‘, * ‘property1‘ => ‘value1‘, * ‘property2‘ => ‘value2‘, * ] * ``` * * 新建的行为必须继承行为类 [[Behavior]]. 可以使用名称或匿名连接行为. * 当用作数组键的名称时, 使用这个名称, 该行为稍后可以检索使用[[getBehavior()]],即添加行为 * 或被分离使用 [[detachBehavior()]],即解除行为. 匿名行为不能检索或分离. * * 此方法中声明的行为将自动(按需)连接到组件 * * @return 返回值为数组的行为配置. */ public function behaviors() { return []; } /** * 判断 _events 中的一个事件是否具有事件处理程序. * @param string $name 事件名 * @return boolean whether there is any handler attached to the event. */ public function hasEventHandlers($name) { $this->ensureBehaviors(); // 判断事件是否存在 $name 否则 调用Event类中的的方法判断是否有处理程序 return !empty($this->_events[$name]) || Event::hasHandlers($this, $name); } /** *将事件处理程序附加到事件. * * 事件处理程序必须是有效的PHP回调. 例如: * * ``` * function ($event) { ... } // anonymous function----匿名函数 * [$object, ‘handleClick‘] // $object->handleClick()---对象方法 * [‘Page‘, ‘handleClick‘] // Page::handleClick()---静态类方法 * ‘handleClick‘ // global function handleClick()---全局函数 * ``` * * 事件处理程序必须定义以下签名, * * ``` * function ($event) * ``` * * `$event`包括与事件关联的参数. * * @param string $name 事件名 * @param callable $handler 事件处理函数 * @param $data 当事件触发时,将数据传递给事件处理程序. * When the event handler is invoked, this data can be accessed via [[Event::data]]. *当事件处理程序被调用时,这些数据可以通过[ [事件::数据] ]来访问 * @param boolean $append是否将新事件处理程序追加到现有的结尾,处理程序列表。如果FALSE,新的处理程序将被插入在现有事件的开始 * @see off() */ public function on($name, $handler, $data = http://www.mamicode.com/null, $append = true)>
yii2 源码分析 Component类分析 (二)
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。