Skip to content

魔术方法

PHP提供了一系列魔术方法, 以双下划线开头, 用于实现特定的功能

PHP 的魔术方法的作用和 Python 的魔术方法非常类似

PHP 所有的魔术方法参考文档

php
<?php
class MagicClass {
  private $data = [];

  // 当尝试访问不可访问的属性时调用
  public function __get($name) {
    echo "__get called for property $name\n";
    return array_key_exists($name, $this->data) ? $this->data[$name] : null;
  }

  // 当尝试设置不可访问的属性时调用
  public function __set($name, $value) {
    echo "__set called for property $name with value $value\n";
    $this->data[$name] = $value;
  }

  // 当检查不可访问的属性是否存在时调用
  public function __isset($name) {
    echo "__isset called for property $name\n";
    return isset($this->data[$name]);
  }

  // 当尝试取消设置不可访问的属性时调用
  public function __unset($name) {
    echo "__unset called for property $name\n";
    unset($this->data[$name]);
  }

  // 当尝试调用不可访问的方法时调用
  public function __call($name, $arguments) {
    echo "__call called for method $name with arguments: " . implode(', ', $arguments) . "\n";
    return "Result of $name";
  }

  // 当尝试调用不可访问的静态方法时调用
  public static function __callStatic($name, $arguments) {
    echo "__callStatic called for static method $name with arguments: " . implode(', ', $arguments) . "\n";
    return "Static result of $name";
  }

  // 当对象被当作字符串使用时调用
  public function __toString() {
    return "This is a MagicClass object\n";
  }

  // 当对象被克隆时调用
  public function __clone() {
    echo "__clone called\n";
    // 深度克隆需要手动处理
    $this->data = array_map(function($value) {
      return (is_object($value)) ? clone $value : $value;
    }, $this->data);
  }

  // 当序列化对象时调用
  public function __sleep() {
    echo "__sleep called\n";
    // 返回需要序列化的属性数组
    return ['data'];
  }

  // 当反序列化对象时调用
  public function __wakeup() {
    echo "__wakeup called\n";
    // 重新建立数据库连接等
  }

  // 当对象被销毁时调用
  public function __destruct() {
    echo "__destruct called\n";
  }

  // 当使用var_dump()或print_r()时调用
  public function __debugInfo() {
    return [
      'data' => $this->data,
      'count' => count($this->data)
    ];
  }
}

// 使用示例
$obj = new MagicClass();

// 调用__set和__get
$obj->name = "张三"; // __set called for property name with value 张三
echo $obj->name;     // __get called for property name \n 张三

// 调用__isset和__unset
var_dump(isset($obj->name)); // __isset called for property name \n bool(true)
unset($obj->name);           // __unset called for property name
var_dump(isset($obj->name)); // __isset called for property name \n bool(false)

// 调用__call
echo $obj->nonExistentMethod("arg1", "arg2");
// __call called for method nonExistentMethod with arguments: arg1, arg2
// Result of nonExistentMethod

// 调用__callStatic
echo MagicClass::staticNonExistentMethod("arg1");
// __callStatic called for static method staticNonExistentMethod with arguments: arg1
// Static result of staticNonExistentMethod

// 调用__toString
echo $obj; // This is a MagicClass object

// 调用__clone
$obj2 = clone $obj; // __clone called

// 序列化与反序列化
$serialized = serialize($obj); // __sleep called
$unserialized = unserialize($serialized); // __wakeup called

// var_dump会调用__debugInfo
var_dump($obj);
/*
object(MagicClass)#1 (2) {
  ["data"]=>
  array(0) {
  }
  ["count"]=>
  int(0)
}
*/

// 析构函数会在脚本结束时自动调用
// __destruct called

Released under the MIT License.