在 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);