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

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

相关推荐
apcipot_rain5 小时前
C++转Java日记(04)
java·开发语言·c++
云和数据.ChenGuang7 小时前
LangGraph 异步 Node 的设计与写法实践
开发语言·人工智能·python·机器学习·php
蜗牛一步步往上爬10 小时前
第十六章 C++语言在深度学习中的应用
开发语言·c++·深度学习
好的佩奇11 小时前
Dart 之扩展方法
android·flutter·dart
张张123y12 小时前
DSH 插件调试避坑:client.js 设置面板、热重载与高频报错排查表
开发语言·javascript·人工智能·开源·ecmascript·后端开发·ai agent
三少爷的鞋12 小时前
换个思路理解:非阻塞挂起
android
好的佩奇13 小时前
蓝牙之经典蓝牙
android·flutter·蓝牙
冻柠檬飞冰走茶15 小时前
字母移动游戏题解:贪心求最长可保留连续子串(附 C 实现)
c语言·开发语言·数据结构·算法·动态规划
FRing0315 小时前
vue2干货总结7(自定义指令、插槽、单页应用程序、路由的使用(VueRouter))
开发语言·前端·vue.js·vue2
雪落漂泊15 小时前
C++算法 二分查找篇(上)
开发语言·c++·算法