PHP魔术方法详解

__construct()

构造函数用于初始化新创建的对象。PHP 5 之后不推荐使用类名作为构造函数。

php 复制代码
class Person {
    public $name;
    public $age;

    public function __construct($name, $age) {
        $this->name = $name;
        $this->age = $age;
    }
}

$person = new Person("Alice", 30);

__destruct()

析构函数在对象被销毁前调用,用于释放资源或进行一些清理操作。

php 复制代码
class Person {
    public function __destruct() {
        // 清理资源或执行其他尾部操作
        echo "Destroying " . $this->name . "\n";
    }
}

$person = new Person("Alice", 30);
unset($person); // 显示销毁对象

__call($name, $arguments)

尝试调用对象中不可访问的方法时调用。

php 复制代码
class Person {
    private function greet($greeting) {
        return $greeting . ", I am " . $this->name;
    }

    public function __call($name, $arguments) {
        if (method_exists($this, $name)) {
            return call_user_func_array([$this, $name], $arguments);
        }
        throw new Exception("Call to undefined method " . __CLASS__ . "::$name");
    }
}

$person = new Person("Alice", 30);
echo $person->greet("Hello"); // 不能直接调用private方法,通过__call间接调用

__callStatic($name, $arguments)

尝试调用类中不可访问的静态方法时调用。

php 复制代码
class Person {
    private static function greet($greeting) {
        return $greeting . ", This is " . __CLASS__;
    }

    public static function __callStatic($name, $arguments) {
        if (method_exists(__CLASS__, $name)) {
            return forward_static_call_array([__CLASS__, $name], $arguments);
        }
        throw new Exception("Call to undefined static method " . __CLASS__ . "::$name");
    }
}

echo Person::greet("Hello"); // 不能直接调用private方法,通过__callStatic间接调用

__get($name)

尝试访问对象中不可访问的属性时调用。

php 复制代码
class Person {
    private $data = array('name' => 'Alice', 'age' => 30);

    public function __get($name) {
        if (array_key_exists($name, $this->data)) {
            return $this->data[$name];
        }
        throw new Exception("Undefined property: " . __CLASS__ . "::$name");
    }
}

$person = new Person();
echo $person->name; // 不能直接访问private属性,通过__get间接访问

__set($name, $value)

尝试设置对象中不可访问的属性时调用。

php 复制代码
class Person {
    private $data = array();

    public function __set($name, $value) {
        $this->data[$name] = $value;
    }
}

$person = new Person();
$person->name = "Alice"; // 不能直接设置private属性,通过__set间接设置

__isset($name)

当对对象中不可访问的属性调用isset()empty()时调用。

php 复制代码
class Person {
    private $data = array('name' => 'Alice', 'age' => 30);

    public function __isset($name) {
        return isset($this->data[$name]);
    }
}

$person = new Person();
var_dump(isset($person->name)); // 输出bool(true)

__unset($name)

尝试对对象中不可访问的属性调用unset()时调用。

php 复制代码
class Person {
    private $data = array('name' => 'Alice', 'age' => 30);

    public function __unset($name) {
        unset($this->data[$name]);
    }
}

$person = new Person();
unset($person->name); // 不能直接unset private属性,通过__unset间接进行

__sleep()

调用serialize()序列化对象时调用。

php 复制代码
class Person {
    public $name;
    public $age;
    private $data;

    public function __construct($name, $age) {
        $this->name = $name;
        $this->age = $age;
        $this->data = rand(); // 数据不适合序列化
    }

    public function __sleep() {
        // 指定序列化时保存的属性
        return array('name', 'age');
    }
}

$person = new Person("Alice", 30);
$serializedPerson = serialize($person);

__wakeup()

调用unserialize()反序列化对象时调用。

php 复制代码
class Person {
    public $name;
    public $age;

    public function __wakeup() {
        // 反序列化之后的操作,例如重新建立数据库连接
        $this->reconnect();
    }

    private function reconnect() {
        // 重建连接的代码
    }
}

$person = unserialize($serializedPerson);

__serialize()

PHP 7.4及以上版本,当你需要自定义对象的序列化逻辑时使用。

php 复制代码
class Person {
    public $name;
    public $age;
    private $data;
    
    public function __serialize(): array {
        // 返回一个数组,包含序列化时需要的所有属性
        return [
            'name' => $this->name,
            'age' => $this->age,
        ];
    }
}

$person = new Person("Alice", 30);
$serializedPerson = serialize($person);

__unserialize(array $data)

PHP 7.4及以上版本,当你需要自定义对象的反序列化逻辑时使用。

php 复制代码
class Person {
    public $name;
    public $age;
    
    public function __unserialize(array $data): void {
        $this->name = $data['name'];
        $this->age = $data['age'];
        // 可以在这里执行其他反序列化后的初始化操作
    }
}

$person = unserialize($serializedPerson);

__toString()

当一个对象被当作字符串使用时自动调用。

php 复制代码
class Person {
    private $name = "Alice";

    public function __toString() {
        return $this->name;
    }
}

$person = new Person();
echo $person; // 输出"Alice"

__invoke()

对象作为函数使用时自动调用。

php 复制代码
class CallablePerson {
    public function __invoke($greeting) {
        return $greeting . ", I am a callable object!";
    }
}

$person = new CallablePerson();
echo $person("Hello"); // 输出"Hello, I am a callable object!"

__set_state($properties)

当使用var_export()导出类的实例时调用。

php 复制代码
class Person {
    public $name;
    public $age;

    public static function __set_state($properties) {
        $obj = new Person();
        $obj->name = $properties['name'];
        $obj->age = $properties['age'];
        return $obj;
    }
}

$person = new Person();
$person->name = "Alice";
$person->age = 30;
echo var_export($person, true); // 导出类的实例

__clone()

当对象被克隆时自动调用,用于深复制对象中的属性。

php 复制代码
class Person {
    public $name;
    public $age;
    public $address;

    public function __clone() {
        // 当包含对象时,确保进行深复制
        $this->address = clone $this->address;
    }
}

$person1 = new Person();
$person1->address = new Address();
$person2 = clone $person1;

__debugInfo()

当使用var_dump()显示对象信息时调用。

php 复制代码
class Person {
    private $data = array('name' => 'Alice', 'age' => 30);

    public function __debugInfo() {
        return [
            'name' => $this->data['name'],
            'age' => $this->data['age'],
            // 隐藏敏感数据或不相关的内部信息
        ];
    }
}

$person = new Person();
var_dump($person);

以上例子提供了一些常见的用法和场景,这些魔术方法让对象的行为更加灵活和可控。

相关推荐
一二小选手13 分钟前
【Java Web】分页查询
java·开发语言
大G哥13 分钟前
python 数据类型----可变数据类型
linux·服务器·开发语言·前端·python
Code成立27 分钟前
《Java核心技术 卷I》用户图形界面鼠标事件
java·开发语言·计算机外设
Yawesh_best1 小时前
MySQL(5)【数据类型 —— 字符串类型】
android·mysql·adb
Xiao Fei Xiangζั͡ޓއއ1 小时前
一觉睡醒,全世界计算机水平下降100倍,而我却精通C语言——scanf函数
c语言·开发语言·笔记·程序人生·面试·蓝桥杯·学习方法
记录无知岁月1 小时前
【MATLAB】目标检测初探
开发语言·yolo·目标检测·matlab·yolov3·yolov2
远望清一色1 小时前
基于MATLAB身份证号码识别
开发语言·图像处理·算法·matlab
NMBG221 小时前
[JAVAEE] 面试题(四) - 多线程下使用ArrayList涉及到的线程安全问题及解决
java·开发语言·面试·java-ee·intellij-idea
Py小趴1 小时前
Python自学之Colormaps指南
开发语言·python·数据可视化
晒足以百八十1 小时前
基于Python 和 pyecharts 制作招聘数据可视化分析大屏
开发语言·python·信息可视化