本文目录导读:

我来详细讲解一下 PHP 中的魔术方法(Magic Methods),这些方法以双下划线 开头,在特定时机被自动调用。
🔮 核心魔术方法
__construct() - 构造函数
class User {
public function __construct($name) {
$this->name = $name;
echo "对象创建成功";
}
}
$user = new User("小明"); // 输出: 对象创建成功
__destruct() - 析构函数
class File {
public function __destruct() {
echo "对象销毁,连接已关闭";
}
}
$file = new File();
unset($file); // 触发析构
__get() - 访问私有属性
class Person {
private $data = ['age' => 25];
public function __get($name) {
echo "试图访问不存在的属性: $name";
return isset($this->data[$name]) ? $this->data[$name] : null;
}
}
$person = new Person();
echo $person->age; // 输出: 试图访问不存在的属性: age 25
__set() - 设置私有属性
class Config {
private $settings = [];
public function __set($name, $value) {
echo "设置动态属性: $name = $value";
$this->settings[$name] = $value;
}
}
$config = new Config();
$config->debug = true; // 输出: 设置动态属性: debug = 1
__call() - 调用不存在的方法
class Calculator {
public function __call($method, $arguments) {
if ($method === 'add') {
return array_sum($arguments);
}
throw new Exception("方法 $method 不存在");
}
}
$calc = new Calculator();
echo $calc->add(1, 2, 3); // 输出: 6
__callStatic() - 调用不存在的静态方法
class MathHelper {
public static function __callStatic($method, $arguments) {
echo "调用静态方法: $method";
return count($arguments);
}
}
echo MathHelper::sum(1, 2, 3); // 输出: 调用静态方法: sum 3
__toString() - 对象转字符串
class Product {
public function __construct($name, $price) {
$this->name = $name;
$this->price = $price;
}
public function __toString() {
return "$this->name: ¥$this->price";
}
}
$product = new Product("手机", 3999);
echo $product; // 输出: 手机: ¥3999
🎯 高级魔术方法
__isset() 和 __unset()
class Data {
private $items = ['name' => '张三', 'email' => 'test@example.com'];
public function __isset($name) {
echo "检查 isset($name)";
return isset($this->items[$name]);
}
public function __unset($name) {
echo "删除 $name";
unset($this->items[$name]);
}
}
$data = new Data();
isset($data->name); // 触发 __isset
unset($data->email); // 触发 __unset
__sleep() 和 __wakeup() - 序列化控制
class Connection {
private $db;
private $data = '重要数据';
public function __sleep() {
echo "序列化前保存数据";
return ['data']; // 只序列化 data 属性
}
public function __wakeup() {
echo "反序列化后重新连接数据库";
$this->db = new PDO('mysql:host=localhost;dbname=test', 'user', 'pass');
}
}
$conn = new Connection();
$serialized = serialize($conn); // 触发 __sleep
$restored = unserialize($serialized); // 触发 __wakeup
__clone() - 克隆对象时
class Database {
public $connection;
public function __construct() {
$this->connection = "数据库连接";
}
public function __clone() {
echo "克隆后重置连接";
$this->connection = "新数据库连接";
}
}
$db1 = new Database();
$db2 = clone $db1; // 触发 __clone
🚀 实用示例:API 请求类
class ApiClient {
private $config = [];
private $headers = [];
public function __construct(array $config = []) {
$this->config = $config;
echo "API 客户端初始化完成\n";
}
// 动态方法调用
public function __call($method, $args) {
if (strpos($method, 'get') === 0) {
$endpoint = strtolower(substr($method, 3));
return $this->request('GET', $endpoint, $args[0] ?? []);
}
throw new BadMethodCallException("方法 $method 不存在");
}
// 动态属性设置
public function __set($key, $value) {
if ($key === 'token' || $key === 'timeout') {
$this->config[$key] = $value;
return;
}
throw new InvalidArgumentException("无效配置项: $key");
}
// 动态属性获取
public function __get($key) {
return $this->config[$key] ?? null;
}
private function request($method, $endpoint, $params = []) {
echo "请求: $method /$endpoint\n";
echo "参数: " . json_encode($params) . "\n";
return "模拟响应";
}
public function __toString() {
return "API 配置: " . json_encode($this->config);
}
public function __debugInfo() {
return ['config' => $this->config, 'headers' => $this->headers];
}
}
// 使用示例
$api = new ApiClient(['base_url' => 'https://api.example.com']);
$api->timeout = 30;
echo $api->timeout . "\n"; // 30
$result = $api->getUsers(['page' => 1]);
echo $api; // 输出配置
📋 注意事项
- 不要混用:魔术方法不能和同名普通方法共存
- 触发条件:只有在对象上下文中才会触发
- 性能考虑:过度使用会影响性能,建议适当使用
- 版本兼容:
__serialize()和__unserialize()是 PHP 7.4+ 新增的
魔术方法提供了强大的钩子机制,可以实现:
- 属性的动态访问控制
- 方法的动态扩展
- 对象序列化控制
- 错误处理和兼容性
合理使用可以极大提升代码的灵活性和可维护性,但要注意不要过度使用,保持代码清晰。