PHP作为一种广泛使用的服务器端脚本语言,不仅因其灵活性受到开发者的青睐,而且还因其提供的众多魔术方法(Magic Methods)而备受欢迎。魔术方法是PHP中的特殊方法,以双下划线(__)开头,它们在特定的情况下会自动被调用,极大地增强了语言的表达力。接下来,我们将深入探索16个对PHP开发者而言必知必会的魔术方法,并通过具体示例来解释它们的用途和工作原理。

1. __construct()

构造方法在创建对象时自动调用,通常用于初始化对象属性。

class MyClass {
    public function __construct() {
        echo "对象已创建";
    }
}
$obj = new MyClass(); // 输出:对象已创建

2. __destruct()

析构方法在对象没有被引用时自动调用,常用于资源的清理工作。

class MyClass {
    public function __destruct() {
        echo "对象被销毁";
    }
}
$obj = new MyClass();
unset($obj); // 输出:对象被销毁

3. __call()

当调用一个对象中不可访问的方法时,__call()方法会被自动调用。

class MyClass {
    public function __call($name, $arguments) {
        echo "调用方法 $name 不存在。参数列表:" . implode(', ', $arguments);
    }
}
$obj = new MyClass();
$obj->nonExistentMethod('参数1', '参数2'); // 输出:调用方法 nonExistentMethod 不存在。参数列表:参数1, 参数2

4. __callStatic()

当调用一个类中不可访问的静态方法时,__callStatic()方法会被自动调用。

class MyClass {
    public static function __callStatic($name, $arguments) {
        echo "调用静态方法 $name 不存在。参数列表:" . implode(', ', $arguments);
    }
}
MyClass::nonExistentStaticMethod('参数1', '参数2'); // 输出:调用静态方法 nonExistentStaticMethod 不存在。参数列表:参数1, 参数2

5. __get()

当读取对象中不可访问的属性时,__get()方法会被自动调用。

class MyClass {
    private $data = array();
    
    public function __get($name) {
        return isset($this->data[$name]) ? $this->data[$name] : null;
    }
}
$obj = new MyClass();
echo $obj->undefinedProp; // 输出:null

6. __set()

当设置对象中不可访问的属性时,__set()方法会被自动调用。

class MyClass {
    private $data = array();
    
    public function __set($name, $value) {
        $this->data[$name] = $value;
    }
}
$obj = new MyClass();
$obj->newProp = '测试';
echo $obj->newProp; // 输出:测试

7. __isset()

当使用isset()或empty()检查对象中不可访问的属性时,__isset()方法会被自动调用。

class MyClass {
    private $data = array("prop" => "存在");
    
    public function __isset($name) {
        return isset($this->data[$name]);
    }
}
$obj = new MyClass();
var_dump(isset($obj->prop)); // 输出:bool(true)
var_dump(isset($obj->undefinedProp)); // 输出:bool(false)

8. __unset()

当使用unset()移除对象中不可访问的属性时,__unset()方法会被自动调用。

class MyClass {
    private $data = array("prop" => "存在");
    
    public function __unset($name) {
        unset($this->data[$name]);
    }
}
$obj = new MyClass();
unset($obj->prop);
var_dump(isset($obj->prop)); // 输出:bool(false)

9. __sleep()

__sleep()方法在使用serialize()函数序列化对象之前自动调用,可以用于清理对象并返回一个包含对象中所有应被序列化的属性名称的数组。

class MyClass {
    public $prop1 = '值1';
    private $prop2 = '值2';
    public $prop3 = '值3';
    
    public function __sleep() {
        return array('prop1', 'prop3');
    }
}
$obj = new MyClass();
$serialized = serialize($obj);
echo $serialized; // 输出:O:7:"MyClass":2:{s:5:"prop1";s:6:"值1";s:5:"prop3";s:6:"值3";}

10. __wakeup()

__wakeup()方法在使用unserialize()函数反序列化对象之后自动调用,用于重建任何资源类型的属性或执行其他初始化操作。

class MyClass {
    public function __wakeup() {
        // 重新初始化操作
    }
}

11. __toString()

当尝试将对象作为字符串输出时,__toString()方法会被自动调用。

class MyClass {
    public function __toString() {
        return "这是一个对象";
    }
}
$obj = new MyClass();
echo $obj; // 输出:这是一个对象

12. __invoke()

当尝试以调用函数的方式调用一个对象时,__invoke()方法会被自动调用。

class MyClass {
    public function __invoke($arg) {
        return "被当作函数调用,参数为:" . $arg;
    }
}
$obj = new MyClass();
echo $obj('测试'); // 输出:被当作函数调用,参数为:测试

13. __set_state()

__set_state()方法用于类中静态方法的声明,当使用var_export()导出类的实例时,此静态方法会被调用。

class MyClass {
    public $prop;
    
    public static function __set_state($an_array) {
        $obj = new MyClass();
        $obj->prop = $an_array['prop'];
        return $obj;
    }
}
$obj = new MyClass();
$obj->prop = '测试';
$exported = var_export($obj, true);
echo $exported; // 输出:MyClass::__set_state(array( 'prop' => '测试', ))

14. __clone()

__clone()方法在对象被克隆时自动调用,用于修改新克隆的对象的属性或执行克隆后的初始化。

class MyClass {
    public $prop;
    
    public function __clone() {
        // 克隆后的操作
    }
}
$obj = new MyClass();
$obj2 = clone $obj;

15. __debugInfo()

__debugInfo()方法在使用var_dump()打印对象信息时自动调用,可以用于控制哪些属性和信息被输出。

class MyClass {
    private $hidden = '隐藏值';
    
    public function __debugInfo() {
        return [
            'revealed' => '这是可见的',
        ];
    }
}
$obj = new MyClass();
var_dump($obj); // 将仅显示revealed属性

16. __serialize() 和 __unserialize()

在PHP 7.4及以上版本中,__serialize()和__unserialize()提供了对对象序列化和反序列化过程的更细粒度控制。

class MyClass {
    private $prop = '值';
    
    public function __serialize(): array {
        return ['prop' => $this->prop];
    }
    
    public function __unserialize(array $data): void {
        $this->prop = $data['prop'];
    }
}
$obj = new MyClass();
$serialized = serialize($obj);
echo $serialized; // 输出序列化后的字符串

$unserialized = unserialize($serialized);
var_dump($unserialized); // 输出反序列化后的对象
艾林博客 - 技术分享、开发经验与AI探索的个人技术博客
艾林博客 - 技术分享、开发经验与AI探索的个人技术博客

延伸阅读:

分布式锁别上 Redlock:把单实例 Redis 的锁写对,就够 99% 的系统用了 架构设计
分布式锁别上 Redlock:把单实例 Redis 的锁写对,就够 99% 的系统用了

Redis 做分布式锁就单实例加看门狗,要正确性就上 etcd,Redlock 卡在中间两头不靠。本文讲清三种方案的真实边界:一把合格的 Redis 锁怎么写(唯一 value、Lua 原子释放、过期时间)、Redlock 为什么解决不了 GC 停顿与 fencing token、以及什么时候该换 etcd 或数据库唯一约束兜底。

后端 优化 安全

Valencio

/

2026-10-21

PHP 8.6 的性能头号卖点,在八月被撤回了 开发编程
PHP 8.6 的性能头号卖点,在八月被撤回了

PHP 8.6 的闭包优化 RFC 以 24:0 通过,但 static 自动推断在 8 月被撤回,那个 3% 只对显式写了 static 的闭包生效;同时 35 项弃用投票有 4 项被否,list() 以 23:23 保住。我把自己的 626 个 PHP 文件扫了一遍,自有代码零命中,升级计划随之改掉。

PHP 后端

Valencio

/

2026-10-16

内存条为什么涨了两倍多:AI 抢的不是内存,是晶圆 系统运维
内存条为什么涨了两倍多:AI 抢的不是内存,是晶圆

两根内存条从 700 多涨到 2000 多,根子不在缺货,在晶圆面积:HBM 每产出 1 bit 要占标准 DDR 三倍的硅片,2026 年吃掉 22% 的 DRAM 产能只交回 9% 的容量。再叠加 60%~70% 的服务器级产能被长协锁死、新产能要 2028 年才算数,这轮周期不会像 2019 年那样崩回去。文章同时给出云账单与内存预留的排查清单。

优化 AI

Valencio

/

2026-10-13