Yii2源码学习之yii\base\Component代码详解

灰太狼 2022-07-15 12:58 250阅读 0赞
  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. namespace yii\base;
  8. use Yii;
  9. /**
  10. * Component is the base class that implements the *property*, *event* and *behavior* features.
  11. * 组件是实现属性、事件、行为的基类
  12. *
  13. * Component provides the *event* and *behavior* features, in addition to the *property* feature which is implemented in
  14. * its parent class [[Object]].
  15. * 组件提供事件和行为,继承他父类Object的特点
  16. *
  17. * Event is a way to "inject" custom code into existing code at certain places. For example, a comment object can trigger
  18. * an "add" event when the user adds a comment. We can write custom code and attach it to this event so that when the event
  19. * is triggered (i.e. comment will be added), our custom code will be executed.
  20. *
  21. * An event is identified by a name that should be unique within the class it is defined at. Event names are *case-sensitive*.
  22. * 事件是一种在特定的地方“注入”自定义代码到现有的代码。例如,
  23. * 当一个用户添加评论事件时,注释的对象可以触发。我们可以编写自定义代码,并将其附加到此事件,这样当事件被触发(即评论将被添加),我们的自定义代码会被执行。
  24. *
  25. * One or multiple PHP callbacks, called *event handlers*, can be attached to an event. You can call [[trigger()]] to
  26. * raise an event. When an event is raised, the event handlers will be invoked automatically in the order they were
  27. * attached.
  28. *
  29. * To attach an event handler to an event, call [[on()]]:
  30. *
  31. * 一个或多个php回调,称为为‘事件处理’。要触发一个事件处理,可以用on();举个例子。
  32. *
  33. * ```php
  34. * $post->on('update', function ($event) {
  35. * // send email notification
  36. * });
  37. * ```
  38. *
  39. * In the above, an anonymous function is attached to the "update" event of the post. You may attach
  40. * the following types of event handlers:
  41. * 一个匿名函数被连接到'update'事件后。可以用以下类型的程序做处理:
  42. *
  43. * - anonymous function: `function ($event) { ... }` 匿名函数
  44. * - object method: `[$object, 'handleAdd']` 对象方法
  45. * - static class method: `['Page', 'handleAdd']` 静态类方法
  46. * - global function: `'handleAdd'` 全局函数
  47. *
  48. * The signature of an event handler should be like the following:
  49. * 一个事件处理程序的签名应该是如下:
  50. *
  51. * ```php
  52. * function foo($event)
  53. * ```
  54. *
  55. * where `$event` is an [[Event]] object which includes parameters associated with the event.
  56. * $event是一个[[Event]]对象 包括与事件相关联的参数。
  57. *
  58. * You can also attach a handler to an event when configuring a component with a configuration array.
  59. * The syntax is like the following:
  60. * 还可以将处理程序附加到配置数组中配置组件的事件。语法如下:
  61. *
  62. * ```php
  63. * [
  64. * 'on add' => function ($event) { ... }
  65. * ]
  66. * ```
  67. *
  68. * where `on add` stands for attaching an event to the `add` event.
  69. * `on add` 代表添加事件
  70. *
  71. * Sometimes, you may want to associate extra data with an event handler when you attach it to an event
  72. * and then access it when the handler is invoked. You may do so by
  73. * 有时,当你将它附加到一个事件时,你可能会把额外的数据与事件处理程序关联起来然后在调用处理程序时访问它。
  74. *
  75. * ```php
  76. * $post->on('update', function ($event) {
  77. * // the data can be accessed via $event->data
  78. * }, $data);
  79. * ```
  80. *
  81. * A behavior is an instance of [[Behavior]] or its child class. A component can be attached with one or multiple
  82. * behaviors. When a behavior is attached to a component, its public properties and methods can be accessed via the
  83. * component directly, as if the component owns those properties and methods.
  84. * 行为是行为的一个实例或它的子类。
  85. * 一个组件可以连接一个或多个行为。
  86. * 当一个行为被连接到一个组件,它的公共属性和方法可以通过访问组件的直接组件,因为组件拥有这些属性和方法。
  87. *
  88. * To attach a behavior to a component, declare it in [[behaviors()]], or explicitly call [[attachBehavior]]. Behaviors
  89. * declared in [[behaviors()]] are automatically attached to the corresponding component.
  90. *
  91. * One can also attach a behavior to a component when configuring it with a configuration array. The syntax is like the
  92. * following:
  93. *
  94. * ```php
  95. * [
  96. * 'as tree' => [
  97. * 'class' => 'Tree',
  98. * ],
  99. * ]
  100. * ```
  101. *
  102. * where `as tree` stands for attaching a behavior named `tree`, and the array will be passed to [[\Yii::createObject()]]
  103. * to create the behavior object.
  104. *
  105. * @property Behavior[] $behaviors List of behaviors attached to this component. This property is read-only.
  106. *
  107. * @author Qiang Xue <qiang.xue@gmail.com>
  108. * @since 2.0
  109. */
  110. //该类继承了Object类
  111. class Component extends Object
  112. {
  113. /**
  114. * @var array the attached event handlers (event name => handlers)
  115. * 存储对象的事件处理程序,是一个数组
  116. */
  117. private $_events = [];
  118. /**
  119. * @var Behavior[]|null the attached behaviors (behavior name => behavior). This is `null` when not initialized.
  120. * 赋值给对象的行为,默认值为null
  121. */
  122. private $_behaviors;
  123. /**
  124. * 重写 Object 中的 getter 方法,返回一个组件的属性值。
  125. *
  126. * Returns the value of a component property.
  127. * 返回组件的属性值
  128. *
  129. * This method will check in the following order and act accordingly:
  130. * 此方法将在下面的顺序检查,并相应地采取行动
  131. *
  132. * - a property defined by a getter: return the getter result
  133. * - a property of a behavior: return the behavior property value
  134. *
  135. * 不要直接调用此方法,因为它是一个PHP魔术方法
  136. * Do not call this method directly as it is a PHP magic method that
  137. * will be implicitly called when executing `$value = $component->property;`.
  138. * @param string $name the property name 参数属性名
  139. * @return mixed the property value or the value of a behavior's property 返回混合属性的值或行为属性的值
  140. * @throws UnknownPropertyException if the property is not defined 如果没有定义,抛出信息
  141. * @throws InvalidCallException if the property is write-only. 该属性是只写的
  142. * @see __set()
  143. */
  144. public function __get($name)
  145. {
  146. $getter = 'get' . $name;
  147. if (method_exists($this, $getter)) {
  148. // read property, e.g. getName()
  149. //如果存在 'get' . $name()方法,在直接调用
  150. return $this->$getter();
  151. } else {
  152. // behavior property
  153. $this->ensureBehaviors(); //确保行为已经绑定
  154. /**
  155. * 判断检查对象或类是否能够获取 $name 属性,
  156. * 如果 behavior 中含有该属性,就返回 behavior 中的这个属性
  157. * 第二个参数为 true(默认是true),则不局限于是否有 getter
  158. */
  159. foreach ($this->_behaviors as $behavior) {
  160. if ($behavior->canGetProperty($name)) {
  161. return $behavior->$name;
  162. }
  163. }
  164. }
  165. if (method_exists($this, 'set' . $name)) {
  166. //如果上面的都不成立,并且存在其set方法,则抛出为只读属性
  167. throw new InvalidCallException('Getting write-only property: ' . get_class($this) . '::' . $name);
  168. } else {
  169. //抛出错误异常
  170. throw new UnknownPropertyException('Getting unknown property: ' . get_class($this) . '::' . $name);
  171. }
  172. }
  173. /**
  174. * Sets the value of a component property. 设置属性值
  175. * This method will check in the following order and act accordingly:
  176. * 此方法将在下面的顺序检查,并相应地采取行动
  177. *
  178. * - a property defined by a setter: set the property value
  179. * - an event in the format of "on xyz": attach the handler to the event "xyz"
  180. * - a behavior in the format of "as xyz": attach the behavior named as "xyz"
  181. * - a property of a behavior: set the behavior property value
  182. *
  183. * 重写 Object 中的 setter 方法,由一个setter定义的属性:设置属性值。
  184. * 如果 $name 是 'on xyz',就会将 xyz 事件添加到该对象中
  185. * 如果 $name 是 'as xyz',就会将 xyz 行为添加到该对象中
  186. * 添加对 behaviors 的处理,循环 behaviors,如果其中有相应的属性,就设置它
  187. *
  188. * Do not call this method directly as it is a PHP magic method that
  189. * will be implicitly called when executing `$component->property = $value;`.
  190. * @param string $name the property name or the event name 属性名或者事件名
  191. * @param mixed $value the property value 属性值
  192. * @throws UnknownPropertyException if the property is not defined 未定义扔出错误
  193. * @throws InvalidCallException if the property is read-only. 抛出信息只读
  194. * @see __get()
  195. */
  196. public function __set($name, $value)
  197. {
  198. $setter = 'set' . $name;//在属性名前面加set构建setter方法
  199. if (method_exists($this, $setter)) {
  200. // set property
  201. //如果存在这个方法,就调用setter方法设置其值
  202. $this->$setter($value);
  203. return;
  204. } elseif (strncmp($name, 'on ', 3) === 0) { //比较$name和'on '前3个字符,如果$name以on+空格开始,就添加事件
  205. // on event: attach event handler
  206. $this->on(trim(substr($name, 3)), $value);//执行on 方法,用来添加附加事件。
  207. return;
  208. } elseif (strncmp($name, 'as ', 3) === 0) {
  209. //如果$name以as+空格开始,就添加行为
  210. // as behavior: attach behavior
  211. $name = trim(substr($name, 3));//截取as后面的字符,用attachBehavior来添加附加行为。
  212. $this->attachBehavior($name, $value instanceof Behavior ? $value : Yii::createObject($value));
  213. //$value这个对象是Behavior类的一个实例,取$value为参数,否则静态调用Yii方法创造一个新的对象。
  214. return;
  215. } else {
  216. // behavior property
  217. $this->ensureBehaviors(); //确保行为已经绑定
  218. foreach ($this->_behaviors as $behavior) {
  219. if ($behavior->canSetProperty($name)) {
  220. //遍历行为,如果行为中有可以设置的属性$name
  221. $behavior->$name = $value;//给该行为类中的属性设置属性值
  222. return;
  223. }
  224. }
  225. }
  226. if (method_exists($this, 'get' . $name)) { //如果上面的都不成立,并且存在getter方法,说明,他是一个只读属性,抛出异常
  227. throw new InvalidCallException('Setting read-only property: ' . get_class($this) . '::' . $name);
  228. } else { //如果不属于这个类,就抛出异常.
  229. throw new UnknownPropertyException('Setting unknown property: ' . get_class($this) . '::' . $name);
  230. }
  231. }
  232. /**
  233. * Checks if a property is set, i.e. defined and not null.
  234. * 属性是否为空
  235. *
  236. * This method will check in the following order and act accordingly:
  237. * 此方法将在下面的顺序检查,并相应地采取行动
  238. *
  239. * - a property defined by a setter: return whether the property is set
  240. * - a property of a behavior: return whether the property is set
  241. * - return `false` for non existing properties
  242. * 重写 Object 中的 isset 方法 通过一个setter定义的属性:返回属性是否设置
  243. * 行为的属性:返回属性值是否设置
  244. *
  245. * Do not call this method directly as it is a PHP magic method that
  246. * will be implicitly called when executing `isset($component->property)`.
  247. * @param string $name the property name or the event name 属性名或事件名
  248. * @return boolean whether the named property is set 属性值是否被设置 返回boolean值。
  249. * @see http://php.net/manual/en/function.isset.php
  250. */
  251. public function __isset($name)
  252. {
  253. $getter = 'get' . $name;
  254. if (method_exists($this, $getter)) {
  255. // 判断是否有getter方法,有 getter 方法且获取的值不为 null,才认为该属性存在
  256. return $this->$getter() !== null;
  257. } else {
  258. // behavior property
  259. $this->ensureBehaviors(); //确定行为已经绑定
  260. foreach ($this->_behaviors as $behavior) {
  261. //遍历行为
  262. if ($behavior->canGetProperty($name)) { // 如果 behavior 中有 $name 属性,且不为 null,该属性存在 返回true
  263. return $behavior->$name !== null;
  264. }
  265. }
  266. }
  267. return false;
  268. }
  269. /**
  270. * Sets a component property to be null.
  271. * 设置属性为null,即删除属性
  272. *
  273. * This method will check in the following order and act accordingly:
  274. * 此方法将在下面的顺序检查,并相应地采取行动
  275. *
  276. * - a property defined by a setter: set the property value to be null
  277. * - a property of a behavior: set the property value to be null
  278. * 重写 Object 中的 unset 方法,
  279. * 通过setter定义的属性:设置该属性值为空
  280. * 属性的行为:将属性值设为空
  281. *
  282. * Do not call this method directly as it is a PHP magic method that
  283. * will be implicitly called when executing `unset($component->property)`.
  284. * @param string $name the property name
  285. * @throws InvalidCallException if the property is read only.
  286. * @see http://php.net/manual/en/function.unset.php
  287. */
  288. public function __unset($name)
  289. {
  290. $setter = 'set' . $name;
  291. if (method_exists($this, $setter)) {
  292. //如果$setter方法存在,通过setter方法把它设置为空
  293. $this->$setter(null);
  294. return;
  295. } else {
  296. // behavior property
  297. $this->ensureBehaviors();
  298. foreach ($this->_behaviors as $behavior) { //遍历行为
  299. if ($behavior->canSetProperty($name)) {
  300. //存在$name值,设为空
  301. $behavior->$name = null;
  302. return;
  303. }
  304. }
  305. }
  306. //抛出异常
  307. throw new InvalidCallException('Unsetting an unknown or read-only property: ' . get_class($this) . '::' . $name);
  308. }
  309. /**
  310. * Calls the named method which is not a class method.
  311. * 当调用的方法不是一个类的方法时
  312. *
  313. * This method will check if any attached behavior has
  314. * the named method and will execute it if available.
  315. * 调用方法名 重写 Object 中的 call 方法,添加对行为的处理,循环 behaviors,如果其中有相应方法,就执行该 behavior 的方法
  316. *
  317. * Do not call this method directly as it is a PHP magic method that
  318. * will be implicitly called when an unknown method is being invoked.
  319. * 不要直接调用该方法,因为它是PHP的魔术方法,当一个未知的方法被调用时,会触发此方法
  320. *
  321. * @param string $name the method name
  322. * @param array $params method parameters
  323. * @return mixed the method return value
  324. * @throws UnknownMethodException when calling unknown method
  325. */
  326. public function __call($name, $params)
  327. {
  328. $this->ensureBehaviors();
  329. foreach ($this->_behaviors as $object) {
  330. //行为中存在名为 $name 的方法,就执行它
  331. //call_user_func_array 调用回调函数,并把一个数组参数作为回调函数的参数
  332. if ($object->hasMethod($name)) {
  333. return call_user_func_array([$object, $name], $params);
  334. }
  335. }
  336. //抛出异常
  337. throw new UnknownMethodException('Calling unknown method: ' . get_class($this) . "::$name()");
  338. }
  339. /**
  340. * This method is called after the object is created by cloning an existing one.
  341. * It removes all behaviors because they are attached to the old object.
  342. * 通过克隆现有创建的对象后,此方法会被调用。
  343. * 他将会消除所有的行为。所有的引用属性 仍然会是一个指向原来的变量的引用
  344. */
  345. public function __clone()
  346. {
  347. // 对象复制时,将它的 _events 设置为空数组,将 _behaviors 设置为 null
  348. $this->_events = [];
  349. $this->_behaviors = null;
  350. }
  351. /**
  352. * Returns a value indicating whether a property is defined for this component.
  353. * 返回一个值,该值指示某属性是否在这个组件中被定义。
  354. *
  355. * A property is defined if:
  356. *
  357. * - the class has a getter or setter method associated with the specified name
  358. * (in this case, property name is case-insensitive);
  359. * - the class has a member variable with the specified name (when `$checkVars` is true);
  360. * - an attached behavior has a property of the given name (when `$checkBehaviors` is true).
  361. *
  362. * 与 Object 中的方法类似,只是添加了是否检测行为的参数
  363. *
  364. * @param string $name the property name 属性名
  365. * @param boolean $checkVars whether to treat member variables as properties 是否将成员变量作为属性
  366. * @param boolean $checkBehaviors whether to treat behaviors' properties as properties of this component 是否将行为属性作为该组件的属性来对待
  367. * @return boolean whether the property is defined 属性是否定义
  368. * @see canGetProperty() 可读
  369. * @see canSetProperty() 可设置
  370. */
  371. public function hasProperty($name, $checkVars = true, $checkBehaviors = true)
  372. {
  373. // $checkVars 参数,用来检查对象是否具有该属性 (不是 getter 和 setter 定义出的属性)
  374. //$checkBehaviors参数,用来设置是否检测behavior
  375. return $this->canGetProperty($name, $checkVars, $checkBehaviors) || $this->canSetProperty($name, false, $checkBehaviors);
  376. }
  377. /**
  378. * Returns a value indicating whether a property can be read.
  379. * 返回一个值,指示是一个属性可读。
  380. * A property can be read if:
  381. *
  382. * - the class has a getter method associated with the specified name
  383. * (in this case, property name is case-insensitive);
  384. * - the class has a member variable with the specified name (when `$checkVars` is true);
  385. * - an attached behavior has a readable property of the given name (when `$checkBehaviors` is true).
  386. *
  387. * 检查对象或类是否能够获取 $name 属性
  388. *
  389. * @param string $name the property name 属性名
  390. * @param boolean $checkVars whether to treat member variables as properties 是否将成员对象作为属性
  391. * @param boolean $checkBehaviors whether to treat behaviors' properties as properties of this component 是否将成员属性作为该组件的属性
  392. * @return boolean whether the property can be read 属性是否可读
  393. * @see canSetProperty()
  394. */
  395. public function canGetProperty($name, $checkVars = true, $checkBehaviors = true)
  396. {
  397. if (method_exists($this, 'get' . $name) || $checkVars && property_exists($this, $name)) {
  398. // 存在 'get' . $name方法 或 存在该属性, 返回true
  399. return true;
  400. } elseif ($checkBehaviors) {
  401. $this->ensureBehaviors();
  402. foreach ($this->_behaviors as $behavior) {
  403. if ($behavior->canGetProperty($name, $checkVars)) {
  404. // behavior 中存在名为 $name 的可读属性,认为该对象也存在 返回true
  405. return true;
  406. }
  407. }
  408. }
  409. return false;
  410. }
  411. /**
  412. * Returns a value indicating whether a property can be set.
  413. * 返回一个值,指示是一个属性是否可写。
  414. *
  415. * A property can be written if:
  416. *
  417. * - the class has a setter method associated with the specified name
  418. * (in this case, property name is case-insensitive);
  419. * - the class has a member variable with the specified name (when `$checkVars` is true);
  420. * - an attached behavior has a writable property of the given name (when `$checkBehaviors` is true).
  421. *
  422. * 检查对象或类是否能够设置 $name 属性
  423. *
  424. * @param string $name the property name 属性名
  425. * @param boolean $checkVars whether to treat member variables as properties 是否将成员变量作为属性
  426. * @param boolean $checkBehaviors whether to treat behaviors' properties as properties of this component 是否将行为属性作为该组件的属性
  427. * @return boolean whether the property can be written 属性是否可写
  428. * @see canGetProperty()
  429. */
  430. public function canSetProperty($name, $checkVars = true, $checkBehaviors = true)
  431. {
  432. if (method_exists($this, 'set' . $name) || $checkVars && property_exists($this, $name)) {
  433. // 存在 'set' . $name方法 或 存在该属性, 返回true
  434. return true;
  435. } elseif ($checkBehaviors) {
  436. $this->ensureBehaviors();
  437. foreach ($this->_behaviors as $behavior) {
  438. // behavior 中存在名为 $name 的可写属性,认为该对象也存在 返回true
  439. if ($behavior->canSetProperty($name, $checkVars)) {
  440. return true;
  441. }
  442. }
  443. }
  444. return false;
  445. }
  446. /**
  447. * Returns a value indicating whether a method is defined.
  448. * 返回一个值,指示是一个方法是否被定义。
  449. * A method is defined if:
  450. *
  451. * - the class has a method with the specified name
  452. * - an attached behavior has a method with the given name (when `$checkBehaviors` is true).
  453. *
  454. * 检查对象或类是否具有 $name 方法
  455. *
  456. * @param string $name the property name 方法名
  457. * @param boolean $checkBehaviors whether to treat behaviors' methods as methods of this component 是否将行为的方法当作这个组件的方法
  458. * @return boolean whether the property is defined 返回波尔型
  459. */
  460. public function hasMethod($name, $checkBehaviors = true)
  461. {
  462. if (method_exists($this, $name)) {
  463. return true;
  464. } elseif ($checkBehaviors) {
  465. //标记是否 check behavior 中的方法
  466. $this->ensureBehaviors();
  467. foreach ($this->_behaviors as $behavior) {
  468. // behavior 中存在名为 $name 的方法,就认为该方法也存在
  469. if ($behavior->hasMethod($name)) {
  470. return true;
  471. }
  472. }
  473. }
  474. return false;
  475. }
  476. /**
  477. * Returns a list of behaviors that this component should behave as.
  478. * 定义该对象中要用到的 behavior
  479. *
  480. * Child classes may override this method to specify the behaviors they want to behave as.
  481. * 可重写
  482. * The return value of this method should be an array of behavior objects or configurations
  483. * indexed by behavior names. A behavior configuration can be either a string specifying
  484. * the behavior class or an array of the following structure:
  485. *
  486. * ```php
  487. * 'behaviorName' => [
  488. * 'class' => 'BehaviorClass',
  489. * 'property1' => 'value1',
  490. * 'property2' => 'value2',
  491. * ]
  492. * ```
  493. *
  494. * Note that a behavior class must extend from [[Behavior]]. Behaviors can be attached using a name or anonymously.
  495. * When a name is used as the array key, using this name, the behavior can later be retrieved using [[getBehavior()]]
  496. * or be detached using [[detachBehavior()]]. Anonymous behaviors can not be retrieved or detached.
  497. * 行为名称可以是字符串或整数。如果是前者,他们是唯一确定的行为。如果是后者,相应的行为是匿名的,它们的特性和方法将无法通过组件提供(仍然可以对组件的事件作出反应)
  498. *
  499. * Behaviors declared in this method will be attached to the component automatically (on demand).
  500. * 在这种方法中声明的行为将自动连接到组件
  501. *
  502. * @return array the behavior configurations. 返回一个数组,行为配置
  503. */
  504. public function behaviors()
  505. {
  506. return [];
  507. }
  508. /**
  509. * Returns a value indicating whether there is any handler attached to the named event.
  510. * 判断 _events 中的一个事件是否具有事件处理程序
  511. *
  512. * @param string $name the event name 事件名
  513. * @return boolean whether there is any handler attached to the event. 返回波尔型,是否有任何处理程序连接到事件
  514. */
  515. public function hasEventHandlers($name)
  516. {
  517. $this->ensureBehaviors();
  518. // 判断事件是否存在 $name 否则 调用Event类中的的方法判断是否有处理程序
  519. return !empty($this->_events[$name]) || Event::hasHandlers($this, $name);
  520. }
  521. /**
  522. * Attaches an event handler to an event.
  523. * 将事件处理程序附加到事件。
  524. *
  525. * The event handler must be a valid PHP callback. The following are
  526. * 事件处理程序必须是有效的PHP回调函数,方便内置方法call_user_fucn()调用
  527. * some examples:
  528. *
  529. * ```
  530. * function ($event) { ... } // anonymous function
  531. * [$object, 'handleClick'] // $object->handleClick()
  532. * ['Page', 'handleClick'] // Page::handleClick()
  533. * 'handleClick' // global function handleClick()
  534. * ```
  535. *
  536. * The event handler must be defined with the following signature,
  537. * 事件处理程序必须用以下签名定义,
  538. *
  539. * ```
  540. * function ($event)
  541. * ```
  542. *
  543. * where `$event` is an [[Event]] object which includes parameters associated with the event.
  544. *
  545. * @param string $name the event name 事件名
  546. * @param callable $handler the event handler 事件处理函数
  547. * @param mixed $data the data to be passed to the event handler when the event is triggered.
  548. * When the event handler is invoked, this data can be accessed via [[Event::data]].
  549. * 当事件被触发时,将传递给事件处理程序的数据。当调用事件处理程序时,该数据可以通过 [[Event::data]] 访问
  550. * @param boolean $append whether to append new event handler to the end of the existing
  551. * handler list. If false, the new handler will be inserted at the beginning of the existing
  552. * handler list.
  553. * 是否将新事件处理程序附加到现有的处理程序列表的结尾。如果是false,新的处理器将被插入在列表的开始的处理程序列表。
  554. * @see off()
  555. */
  556. public function on($name, $handler, $data = null, $append = true)
  557. {
  558. $this->ensureBehaviors();
  559. //$append 判断是否添加到事件(event)的后面,确保_events中有该事件
  560. if ($append || empty($this->_events[$name])) {
  561. //将事件处理程序和参数添加到event数组末尾
  562. $this->_events[$name][] = [$handler, $data];
  563. } else {
  564. //否则 添加到 event 的前面
  565. array_unshift($this->_events[$name], [$handler, $data]);
  566. }
  567. }
  568. /**
  569. * Detaches an existing event handler from this component.
  570. * 将现有的事件处理程序从该组件删除
  571. * This method is the opposite of [[on()]].
  572. * [[on()]]的反方法,用于删除事件处理程序
  573. * @param string $name event name 事件名
  574. * @param callable $handler the event handler to be removed. 事件处理程序
  575. * If it is null, all handlers attached to the named event will be removed. 如果为空,清除所有该名称的事件处理程序
  576. * @return boolean if a handler is found and detached 是否发现并分离的处理程序
  577. * @see on()
  578. */
  579. public function off($name, $handler = null)
  580. {
  581. $this->ensureBehaviors();
  582. // 相应的事件不存在,返回false
  583. if (empty($this->_events[$name])) {
  584. return false;
  585. }
  586. //没有handler,清除该事件的所有事件处理程序 并返回true
  587. if ($handler === null) {
  588. unset($this->_events[$name]);
  589. return true;
  590. } else {
  591. $removed = false;//标记
  592. foreach ($this->_events[$name] as $i => $event) {
  593. if ($event[0] === $handler) { //遍历该事件 判断事件处理程序是否符合
  594. unset($this->_events[$name][$i]); //删除该事件处理程序
  595. $removed = true; //标记
  596. }
  597. }
  598. if ($removed) {
  599. // 如果删除成功,就需要重新构建以下索引,重新赋值
  600. $this->_events[$name] = array_values($this->_events[$name]);
  601. }
  602. return $removed;//返回标记
  603. }
  604. }
  605. /**
  606. * Triggers an event. 触发事件
  607. * This method represents the happening of an event. 此方法表示事件的发生。
  608. * It invokes all attached handlers for the event including class-level handlers.
  609. * 它调用了事件的所有附加处理程序,包括类级处理程序
  610. *
  611. * @param string $name the event name 事件名
  612. * @param Event $event the event parameter. If not set, a default [[Event]] object will be created.
  613. * 事件参数. 如果未设置,默认的 [[Event]] 对象将被创建.
  614. */
  615. public function trigger($name, Event $event = null)
  616. {
  617. //确保行为绑定
  618. $this->ensureBehaviors();
  619. if (!empty($this->_events[$name])) {
  620. // 事件名不为空 构建Event对象,为传入到handler函数中做准备
  621. if ($event === null) {
  622. $event = new Event;
  623. }
  624. if ($event->sender === null) {
  625. $event->sender = $this;
  626. }
  627. $event->handled = false;
  628. $event->name = $name;
  629. foreach ($this->_events[$name] as $handler) {
  630. // 遍历事件 给事件的data属性赋值
  631. $event->data = $handler[1];
  632. // handler的函数中传入了一个Event对象
  633. call_user_func($handler[0], $event);
  634. // stop further handling if the event is handled
  635. // 事件是否被处理,如果了处理事件即handled被设置为true时,停止进一步处理
  636. if ($event->handled) {
  637. return;
  638. }
  639. }
  640. }
  641. // invoke class-level attached handlers [[Event]] 的方法,触发类级别的事件处理程序
  642. Event::trigger($this, $name, $event);
  643. }
  644. /**
  645. * Returns the named behavior object.
  646. * 返回指定的行为对象。
  647. *
  648. * @param string $name the behavior name
  649. * @return null|Behavior the behavior object, or null if the behavior does not exist
  650. */
  651. public function getBehavior($name)
  652. {
  653. //确保行为绑定
  654. $this->ensureBehaviors();
  655. //_behaviors中的行为类存在,返回行为类名,否则返回空
  656. return isset($this->_behaviors[$name]) ? $this->_behaviors[$name] : null;
  657. }
  658. /**
  659. * Returns all behaviors attached to this component. 获取所有的行为类
  660. * @return Behavior[] list of behaviors attached to this component
  661. */
  662. public function getBehaviors()
  663. {
  664. //确保行为绑定
  665. $this->ensureBehaviors();
  666. //直接返回所有行为
  667. return $this->_behaviors;
  668. }
  669. /**
  670. * Attaches a behavior to this component.内部使用的添加一个行为到该组件
  671. * This method will create the behavior object based on the given
  672. * configuration. After that, the behavior object will be attached to
  673. * this component by calling the [[Behavior::attach()]] method.
  674. * 通过提供的配置文件创建一个Behavior对象,通过调用 [[Behavior::attach()]] 方法添加行为到组件.
  675. * @param string $name the name of the behavior. 行为名
  676. * @param string|array|Behavior $behavior the behavior configuration. This can be one of the following: behavior配置
  677. *
  678. * - a [[Behavior]] object 一个[[Behavior]]类
  679. * - a string specifying the behavior class 一个字符串形式的指定行为类
  680. * - an object configuration array that will be passed to [[Yii::createObject()]] to create the behavior object. 一个配置文件数组,通过调用[[Yii::createObject()]] 创建一个行为对象.
  681. *
  682. * @return Behavior the behavior object 行为对象
  683. * @see detachBehavior()
  684. */
  685. public function attachBehavior($name, $behavior)
  686. {
  687. $this->ensureBehaviors(); //确保行为绑定
  688. return $this->attachBehaviorInternal($name, $behavior); //添加行为
  689. }
  690. /**
  691. * Attaches a list of behaviors to the component. 添加行为列表到组件
  692. * Each behavior is indexed by its name and should be a [[Behavior]] object,
  693. * a string specifying the behavior class, or an configuration array for creating the behavior.
  694. * 行为类通过行为名索引,且必须是一个 [[Behavior]] 对象指定的行为类或者一个配置数组
  695. * @param array $behaviors list of behaviors to be attached to the component 行为列表
  696. * @see attachBehavior()
  697. */
  698. public function attachBehaviors($behaviors)
  699. {
  700. $this->ensureBehaviors(); //确保行为绑定
  701. foreach ($behaviors as $name => $behavior) {
  702. //添加行为列表
  703. $this->attachBehaviorInternal($name, $behavior);
  704. }
  705. }
  706. /**
  707. * Detaches a behavior from the component.从组件解除行为
  708. * The behavior's [[Behavior::detach()]] method will be invoked. 通过[[Behavior::detach()]]解除行为
  709. * @param string $name the behavior's name. 行为名
  710. * @return null|Behavior the detached behavior. Null if the behavior does not exist. 存在返回分离行为 不存在返回null
  711. */
  712. public function detachBehavior($name)
  713. {
  714. $this->ensureBehaviors(); //确保行为绑定
  715. if (isset($this->_behaviors[$name])) { //行为存在,解除行为
  716. $behavior = $this->_behaviors[$name];
  717. unset($this->_behaviors[$name]);
  718. //返回分离行为
  719. $behavior->detach();
  720. return $behavior;
  721. } else {
  722. return null;
  723. }
  724. }
  725. /**
  726. * Detaches all behaviors from the component. 解除所有行为
  727. */
  728. public function detachBehaviors()
  729. {
  730. $this->ensureBehaviors(); //确保行为绑定
  731. foreach ($this->_behaviors as $name => $behavior) {
  732. //遍历解除行为
  733. $this->detachBehavior($name);
  734. }
  735. }
  736. /**
  737. * Makes sure that the behaviors declared in [[behaviors()]] are attached to this component.
  738. * 确保声明的行为都被添加到组件
  739. */
  740. public function ensureBehaviors()
  741. {
  742. if ($this->_behaviors === null) {
  743. $this->_behaviors = [];
  744. foreach ($this->behaviors() as $name => $behavior) {
  745. //遍历$this->behaviors()中的behaviors,并添加到$this->_behaviors数组中
  746. $this->attachBehaviorInternal($name, $behavior);
  747. }
  748. }
  749. }
  750. /**
  751. * Attaches a behavior to this component. 内部使用的为该对象添加behavior的方法
  752. * @param string|integer $name the name of the behavior. If this is an integer, it means the behavior
  753. * is an anonymous one. Otherwise, the behavior is a named one and any existing behavior with the same name
  754. * will be detached first. 行为名. 如果是整数,说明该行为是匿名的
  755. * @param string|array|Behavior $behavior the behavior to be attached 添加的行为 string|array|Behavior
  756. * @return Behavior the attached behavior. 返回behavior对象
  757. */
  758. private function attachBehaviorInternal($name, $behavior)
  759. {
  760. if (!($behavior instanceof Behavior)) {
  761. // $behavior不是Behavior对象,认为是配置,则创建一个$behavior对象
  762. $behavior = Yii::createObject($behavior);
  763. }
  764. if (is_int($name)) {
  765. //行为是整数,绑定到组件
  766. $behavior->attach($this);
  767. $this->_behaviors[] = $behavior;
  768. } else {
  769. if (isset($this->_behaviors[$name])) {
  770. // 如果有同名的行为存在就先解绑掉
  771. $this->_behaviors[$name]->detach();
  772. }
  773. $behavior->attach($this);//重新绑定行为到组件
  774. $this->_behaviors[$name] = $behavior;
  775. }
  776. return $behavior;
  777. }
  778. }

发表评论

表情:
评论列表 (有 0 条评论,250人围观)

还没有评论,来说两句吧...

相关阅读

    相关 YII2 GirdView详解(二)

    其他都没变,URL 只显示「请求地址」(因为地址太长了不方便显示),但是同时能满足URL模糊搜索的需求。 <?= GridView::widget([

    相关 yii2学习笔记

    yii2 model 每个模型对应一张表,rules方法定义对应的字段格式,长度。attributeLabels设置对应字段名的默认显示名。 yii2 form 每个