之前我们说过 Yii2 中大多数类都继承自 yii/base/Object,今天就让我们来看一下这个类。
Object 是一个基础类,实现了属性的功能,其基本内容如下:
<?php namespace yii/base; use Yii; /** * Object 是一个基础类,实现了属性的功能 * Yii最基础的类,大多数类都继承了该类 */ class Object implements Configurable { /** * 获取静态方法调用的类名。返回类的名称,如果不是在类中调用则返回 FALSE。 */ public static function className() { ... } /** * Constructor. */ public function __construct($config = []) { ... } /** * 初始化对象 */ public function init() { } /** * 魔术方法,实现 getter */ public function __get($name) { ... } /** * 魔术方法,实现 setter */ public function __set($name, $value) { ... } /** * 魔术方法,实现 isset,基于 getter 实现,有 getter 方法的属性才算存在 */ public function __isset($name) { ... } /** * 魔术方法,实现 unset,基于 setter 实现,有 setter 方法的属性才能 unset 掉 */ public function __unset($name) { ... } /** * Calls the named method which is not a class method. */ public function __call($name, $params) { ... } /** * 检查对象或类是否具有 $name 属性,如果 $checkVars 为 true,则不局限于是否有 getter/setter */ public function hasProperty($name, $checkVars = true) { ... } /** * 检查对象或类是否能够获取 $name 属性,如果 $checkVars 为 true,则不局限于是否有 getter */ public function canGetProperty($name, $checkVars = true) { ... } /** * 检查对象或类是否能够设置 $name 属性,如果 $checkVars 为 true,则不局限于是否有 setter */ public function canSetProperty($name, $checkVars = true) { ... } /** * 检查对象或类是否具有 $name 方法 */ public function hasMethod($name) { ... } }
如果想看详细的注释的话,可以访问 https://github.com/ReadCode/yii2-2.0.3-annotated/blob/master/framework/base/Object.php
从上面的内容中,我们可以看到 Object 类重写了 __get 和 __set 方法,下面我们来详细看下这两个方法:
/** * Returns the value of an object property. * * Do not call this method directly as it is a PHP magic method that * will be implicitly called when executing `$value = $object->property;`. * * 魔术方法,实现 getter * * @param string $name the property name * @return mixed the property value * @throws UnknownPropertyException if the property is not defined * @throws InvalidCallException if the property is write-only * @see __set() */ public function __get($name) { $getter = 'get' . $name; if (method_exists($this, $getter)) { // 对象存在 $getter 方法,就直接调用 return $this->$getter(); } elseif (method_exists($this, 'set' . $name)) { // 如果存在 'set' . $name 方法,就认为该属性是只写的 throw new InvalidCallException('Getting write-only property: ' . get_class($this) . '::' . $name); } else { // 否则认为该属性不存在 throw new UnknownPropertyException('Getting unknown property: ' . get_class($this) . '::' . $name); } } /** * Sets value of an object property. * * Do not call this method directly as it is a PHP magic method that * will be implicitly called when executing `$object->property = $value;`. * * 魔术方法,实现 setter * * @param string $name the property name or the event name * @param mixed $value the property value * @throws UnknownPropertyException if the property is not defined * @throws InvalidCallException if the property is read-only * @see __get() */ public function __set($name, $value) { $setter = 'set' . $name; if (method_exists($this, $setter)) { // 对象存在 $setter 方法,就直接调用 $this->$setter($value); } elseif (method_exists($this, 'get' . $name)) { // 如果存在 'get' . $name 方法,就认为该属性是只读的 throw new InvalidCallException('Setting read-only property: ' . get_class($this) . '::' . $name); } else { // 否则认为该属性不存在 throw new UnknownPropertyException('Setting unknown property: ' . get_class($this) . '::' . $name); } }
基于上面的代码,我们可以看到,如果访问一个 Object 对象的某个属性, Yii会调用名为 get属性名() 的函数。如, SomeObject->Foo , 会自动调用 SomeObject->getFoo() 。 如果修改某一属性,会调用相应的setter函数。 如, SomeObject->Foo = $someValue ,会自动调用 SomeObject->setFoo($someValue) 。
以 SomeObject 的 Foo 为例,如果只存在 getFoo() 方法,那它就是只读的,如果只存在 setFoo() 方法,那它就是只写的,只有两个方法都存在的时候才是既可读又可写的。
需要注意的一点是只有在读取和写入对象的一个不存在的成员变量时, __get() __set() 会被自动调用。 如果 Foo 是一个 public 的属性就不会经过 __get() 和 __set() 方法了。
所以通常属性是 private 的,举个例子如下:
class User extends yii/base/Object { private $_name; public function getName() { return $this->_name; } public function setName($name) { $this->_name = trim($name); } }
我们还可以在 get 和 set 方法中做一些特殊的处理。
除了 __get() __set() 之外, yii/base/Object 还提供了以下方法便于使用属性:
对 Yii2 源码有兴趣的同学可以关注项目 yii2-2.0.3-annotated ,现在在上面已经添加了不少关于 Yii2 源码的注释,之后还会继续添加~
有兴趣的同学也可以参与进来,提交 Yii2 源码的注释。