<?php
/**
* Checks if a property value is null.
* 检查属性值是否为空。
* This method will check in the following order and act accordingly:
* 此方法将在以下顺序检查并相应地采取行动:
* - a property defined by a setter: return whether the property value is null
* 通过setter定义的属性:返回是否将属性值为空
* - a property of a behavior: return whether the property value is null
* 属性的行为:返回属性值是否为空
* Do not call this method directly as it is a PHP magic method that
* will be implicitly called when executing `isset($component->property)`.
*
* 重写 Object 中的 isset 方法,添加对 behaviors 的处理,循环 behaviors,如果其中有相应的属性,就认为有
*
* @param string $name the property name or the event name
* @return boolean whether the named property is null
*/
public function __isset($name)
{
$getter = 'get' . $name;
if (method_exists($this, $getter)) {
// 如果 $getter 方法存在,且不为 null,就返回 true
return $this->$getter() !== null;
} else {
// behavior property
$this->ensureBehaviors();
// 循环所有的 behavior
foreach ($this->_behaviors as $behavior) {
if ($behavior->canGetProperty($name)) {
// 如果 behavior 中有 $name 属性,且不为 null,就返回 true
return $behavior->$name !== null;
}
}
}
return false;
}
/**
* Sets a component property to be null.
* 将组件属性设置为空。
* This method will check in the following order and act accordingly:
* 此方法将在以下顺序检查并相应地采取行动:
* - a property defined by a setter: set the property value to be null
* 通过setter定义的属性:设置该属性值为空
* - a property of a behavior: set the property value to be null
* 属性的行为:将属性值设为空
* Do not call this method directly as it is a PHP magic method that
* will be implicitly called when executing `unset($component->property)`.
*
* 重写 Object 中的 unset 方法,添加对 behaviors 的处理,循环 behaviors,如果其中有相应的属性,设置为空
*
* @param string $name the property name
* @throws InvalidCallException if the property is read only.
*/
public function __unset($name)
{
$setter = 'set' . $name;
if (method_exists($this, $setter)) {
// 如果 $setter 方法存在,且不为 null,就返回 true
$this->$setter(null);
return;
} else {
// behavior property
$this->ensureBehaviors();
// 循环所有的 behavior
foreach ($this->_behaviors as $behavior) {
if ($behavior->canSetProperty($name)) {
// 如果 behavior 中有 $name 属性,就将该属性设为 null
$behavior->$name = null;
return;
}
}
}
throw new InvalidCallException('Unsetting an unknown or read-only property: ' . get_class($this) . '::' . $name);
}
/**
* Calls the named method which is not a class method.
* 称为非类方法的命名方法。
* This method will check if any attached behavior has
* the named method and will execute it if available.
*
* Do not call this method directly as it is a PHP magic method that
* will be implicitly called when an unknown method is being invoked.
*
* 重写 Object 中的 call 方法,添加对 behaviors 的处理,循环 behaviors,如果其中有相应方法,就执行该 behavior 的方法
*
* @param string $name the method name
* @param array $params method parameters
* @return mixed the method return value
* @throws UnknownMethodException when calling unknown method
*/
public function __call($name, $params)
{
$this->ensureBehaviors();
foreach ($this->_behaviors as $object) {
if ($object->hasMethod($name)) {
// behavior 中存在名为 $name 的方法,就执行它
// call_user_func_array — 调用回调函数,并把一个数组参数作为回调函数的参数
return call_user_func_array([$object, $name], $params);
}
}
throw new UnknownMethodException('Calling unknown method: ' . get_class($this) . "::$name()");
}
/**
* This method is called after the object is created by cloning an existing one.
* It removes all behaviors because they are attached to the old object.
*
* 执行 clone 时,将其 _events 和 _behaviors 设置为空
* 对象复制可以通过 clone 关键字来完成(如果可能,这将调用对象的 __clone() 方法)。对象中的 __clone() 方法不能被直接调用。
* ~~~
* $copy_of_object = clone $object;
* ~~~
* 当对象被复制后,PHP 5 会对对象的所有属性执行一个浅复制(shallow copy)。所有的引用属性 仍然会是一个指向原来的变量的引用。
*/
public function __clone()
{
// 对象复制时,将它的 _events 设置为空数组,将 _behaviors 设置为 null
$this->_events = [];
$this->_behaviors = null;
}