引用一个偷学来的概念:
成员变量是一个“内”概念,反映类的结构构成。属性是一个“外”概念,反映的是类的逻辑意义。
成员变量没有读写权限的控制,而属性可以指定只读只写,或可读或可写。
成员变量不对读出做任何后处理,不对写入做任预处理,而属性可以。
public成员变量可以视作没有任何后处理读操作以及没有任何预处理写操作的属性,而private由于外部不可见,不符合属性的“外”概念,所以不能视为属性。
大多数情况,属性会由成员变量来表示,但是属性和成员变量没有必然的对应关系。
通常情况下,将类的成员变量定义为private这样好处一个是为了类的封装性,同时能体现良好的变成习惯。但是对于成员变量的读写操作是非常繁琐的,因此,在PHP5中定义了两个魔法方法,__set()和__get(),在读取一个不存在的成员变量时候,会自动调用_set和_get,这两个方法不是默认存在,需要我们手动添加到类中。
class Fruit { private $color; private $weight; public function __set($name,$value){ $this->$name = $value; } public function __get($name){ return $this->$name; } }
以上类Fruit中有两个私有的成员变量,设置了__set和__get以后,可以直接通过下面这种方式对成员变量进行调用。
$fruit = new Fruit(); $fruit->color = 'red'; echo $fruit->color;如果没有__set和__get,直接通过$fruit->color这种方式调用,则会出错。
利用这一特点,可以实现对单一属性的set和get操作,同时在读操作的时候进行后处理以及在写操作的时候进行预处理。
class Fruit { private $color; private $weight; public function __get($name) // 这里$name是属性名 { $getter = 'get' . $name; // getter函数的函数名 if (method_exists($this, $getter)) { return $this->$getter(); // 调用了getter函数 } elseif (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是属性名,$value是拟写入的属性值 public function __set($name, $value) { $setter = 'set' . $name; // setter函数的函数名 if (method_exists($this, $setter)) { $this->$setter($value); // 调用setter函数 } elseif (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); } } public function setColor($value){ if(trim($value)){ $this->color = $value; } } public function getColor(){ return 'The color is ' . $this->color; } }这样可以在属性写操作的时候,对属性赋值进行trim处理,对属性读的时候,添加了一个一个字符串。
$fruit = new Fruit(); $fruit->color = ' red'; echo $fruit->color;打印结果如下:
The color is red
同样,Yii2框架中Object类就是适用这个特性实现对private成员变量的setter和getter。