特征
- __两个下划线开始
- 不需要显示的调用,由某些条件下触发(类似数据库中的隐式触发器)
__construct()
在对象初始化时调用,通常用来初始化成员变量,或者初始化方法
__destruct()
在对象销毁时调用,通常用来清理操作
属性的重载
定义了一个当访问不存在的属性和方法时,发生自定义的操作
__get($name)
在访问一个不存在的属性时调用,
class Device {
public function __get($name) {
if(array_key_exists($name, $this->data)) {
return $this->data[$name];
}
return null;
}
}
该魔术方法最常用的地方就是通过创建一个“只读”的属性来扩展访问控制。在上面的Battery类中,有一个私有属性$charge,我们可以通过__get()魔术方法将该属性扩展为在类外部可读但不能修改。代码如下
class Battery {
private $charge = 0;
public function __get($name) {
if(isset($this->$name)) {
return $this->$name;
}
return null;
}
}
__set($name, $value)
__set()魔术方法在我们尝试修改一个不可访问的属性时会被调用,它接收两个参数,一个表示属性的名字,一个表示属性的值。示例代码如下:
class Device {
public function __set($name, $value) {
// use the property name as the array key
$this->data[$name] = $value;
}
}
__isset($name)
__isset()魔术方法在对一个不可访问的属性调用isset()方法时会被调用,它接收一个参数,表示属性的名字。它应该返回一个布尔值,用来表示该属性是否存在。代码如下:
class Device {
public function __isset($name) {
return array_key_exists($name, $this->data);
}
}
__unset($name)
__unset()魔术方法在调用unset()函数销毁一个不能访问的属性时会被调用,它接收一个参数,表述属性的名字。
__toString()
__toString()在我们将对象当作字符串一样使用时会被调用,它不接收任何参数。类似java中的。toString()函数输出自定义的信息内容。
克隆对象 __clone()
默认的,对象都是按引用传值的。因此,在将一个对象赋值给另一个变量时,只是创建了指向该对象的一个引用,并没有复制该对象。为了实现真正得复制一个对象,我们需要使用clone关键字。
这种“按引用传递”的策略同样适用于包含在对象内部的对象。即使我们克隆了一个对象,在对象内部的任何对象都不会被克隆,因此最终的结果是两个对象共享了同一个内部对象。示例代码如下:
$device = new Device(new Battery(), 'iMagic');
$device2 = clone $device;
$device->battery->setCharge(65);
echo $device2->battery->charge;
// 65
__clone()魔术方法__clone()可以解决上面的问题。当对一个对象使用clone关键字时,该魔术方法会被调用。在这个魔术方法里,我们可以实现任何子对象的克隆,代码如下:
class Device {
...
public function __clone() {
// copy our Battery object
$this->battery = clone $this->battery;
}
...
}
__call()
魔术方法__call()在调用不存在或不可访问的方法时会被调用。它接收两个参数,一个是调用的方法的名字,一个是包含函数参数的数组。我们可以使用这种方法调用子对象中得同名函数。
//方法不存在时报错
public function __call($name, $args)
{
Support::Error('访问的方法不存在');
}