在 PHP 中,以两个下划线 __
开头的方法被称为魔术方法,它们在特定场景下会自动被调用,以下是一些常见的魔术方法:
1.__construct()
:类的构造函数,在对象创建完成后第一个自动调用,用于执行初始化任务,如对成员属性赋予初始值。每个类若未显式声明,会默认存在一个无参且内容为空的构造方法。同一类中只能声明一个构造方法,PHP 不支持构造函数重载。例如:
class Person {public $name;public $age;public function __construct($name = "", $age = 22) {$this->name = $name;$this->age = $age;}public function say() {echo "我叫:". $this->name. ",年龄:". $this->age;}
}
$person1 = new Person();
echo $person1->say(); // 输出:我叫:,年龄:22
$person2 = new Person("小明", 18);
echo $person2->say(); // 输出:我叫:小明,年龄:18
2.__destruct()
:类的析构函数,当对象不再被使用、即将被销毁时调用,可用于执行清理工作,如关闭文件句柄、释放资源等。
class FileHandler {private $file;public function __construct($filename) {$this->file = fopen($filename, 'r');}public function __destruct() {if ($this->file) {fclose($this->file);}}
}
3.__call()
:当调用对象中不存在的方法时触发,可用于捕获方法调用,实现如代理模式(在代理类中定义一个捕获方法,代理类中没有这个方法时去调用真实对象里的方法)等设计模式。它接收两个参数,$name
为方法名,$arguments
为方法参数数组。
class Proxy {public function __call($name, $arguments) {echo "调用了不存在的方法 $name ,参数为:". implode(', ', $arguments);}
}
$proxy = new Proxy();
$proxy->nonexistentMethod('param1', 'param2');
4.__callStatic()
:在静态上下文中调用不存在的静态方法时执行,与 __call()
类似,用于处理静态方法的动态调用。
class StaticProxy {public static function __callStatic($name, $arguments) {echo "调用了不存在的静态方法 $name ,参数为:". implode(', ', $arguments);}
}
StaticProxy::nonexistentStaticMethod('param1', 'param2');
5.__get()
:当读取一个不存在的属性时调用,可用于实现属性的重载。
class PropertyOverload {private $data = [];public function __get($name) {return $this->data[$name]?? null;}
}
$obj = new PropertyOverload();
echo $obj->nonExistentProperty;
6.__set()
:在给一个不存在的属性赋值时触发。
class PropertyOverload {private $data = [];public function __set($name, $value) {$this->data[$name] = $value;}
}
$obj = new PropertyOverload();
$obj->newProperty = "value";
7.__isset()
:使用 isset()
或 empty()
检测一个不存在的属性时调用。
class PropertyCheck {private $data = [];public function __isset($name) {return isset($this->data[$name]);}
}
$obj = new PropertyCheck();
var_dump(isset($obj->nonExistentProperty));
8.__unset()
:使用 unset()
销毁一个不存在的属性时触发。
class PropertyDestroy {private $data = [];public function __unset($name) {if (isset($this->data[$name])) {unset($this->data[$name]);}}
}
$obj = new PropertyDestroy();
$obj->property = "value";
unset($obj->property);
9.__toString()
:当对象被当作字符串使用(如在 echo
语句中)时调用,用于定义对象的字符串表示形式。
class ObjectToString {public function __toString() {return "这是一个对象";}
}
$obj = new ObjectToString();
echo $obj;
10.__invoke()
:尝试以调用函数的方式调用对象时触发,使对象可像闭包一样被调用。
class InvokableObject {public function __invoke($param) {echo "对象被调用,参数为:". $param;}
}
$obj = new InvokableObject();
$obj('test');
补充(闭包:closure = function() use (var) { echo var; };这行代码,closure是一个变量,它被赋值为一个匿名函数,就是function() { echo var; }这部分。use (var)的意思是,让这个匿名函数可以访问外部的$var变量。然后在函数内部,用echo var;来输出这个变量的值。这样就定义好了一个闭包。当你调用closure();的时候,它就会执行匿名函数里的代码,也就是输出$var的值。n'b)
11.__sleep()
:在序列化对象时调用,可清理对象并返回一个包含所有要序列化属性名称的数组。(可以进行清理工作,同时会返回数组里面是你要序列化的属性,我的理解是轻减了序列化的内容)
class SerializableObject {private $data1;private $data2;public function __sleep() {return ['data1', 'data2'];}
}
$obj = new SerializableObject();
$serialized = serialize($obj);
12.__wakeup()
:PHP 反序列化对象时调用,通常用于重新建立数据库连接或执行其他初始化任务。(和__sleep相反,可以重新连接数据库,恢复数据等操作)
class SerializableObject {private $data1;private $data2;public function __wakeup() {// 重新建立数据库连接等初始化操作}
}
$serialized = '...'; // 假设已存在序列化后的字符串
$obj = unserialize($serialized);