首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP 魔術方法完整圖鑑:從建構子到序列化、呼叫攔截與物件呼叫的 17 個關鍵方法

     編輯:PHP 相關知識

PHP 魔術方法完整圖鑑:從建構子到序列化、呼叫攔截與物件呼叫的 17 個關鍵方法

魔術方法以 __ 雙底線開頭,由特定事件自動觸發,無需手動呼叫。掌握它們能解鎖 PHP 物件導向的高階能力。

生命週期三劍客

方法觸發時機典型用途參數/回傳
__construct()實例化 new Class()依賴注入、資源初始化、驗證參數任意參數,無回傳
__destruct()物件銷毀(無引用/腳本結束)關閉連線、釋放鎖、寫入日誌無參數,無回傳
__clone()clone $obj深層複製內部物件、重置唯一識別碼無參數,無回傳

屬性多載(Property Overloading)

處理不可存取屬性(不存在、protected/private)的讀寫檢查:

方法觸發操作參數回傳
__get($name)讀取 $obj->prop屬性名屬性值
__set($name, $value)寫入 $obj->prop = $val屬性名、值無
__isset($name)isset($obj->prop)屬性名bool
__unset($name)unset($obj->prop)屬性名無

實戰:動態資料容器 + 唯讀屬性

class Device {
    private $data = [];
    private $readonly = ['id', 'created_at'];
    
    public function __get($name) {
        return $this->data[$name] ?? null;
    }
    
    public function __set($name, $value) {
        if (in_array($name, $this->readonly, true)) {
            throw new LogicException("屬性 {$name} 為唯讀");
        }
        $this->data[$name] = $value;
    }
    
    public function __isset($name) {
        return isset($this->data[$name]);
    }
    
    public function __unset($name) {
        if (in_array($name, $this->readonly, true)) return;
        unset($this->data[$name]);
    }
}

物件轉換與表示

方法觸發時機回傳注意
__toString()echo $obj、(string)$objstring拋出例外會致命錯誤
__invoke($args...)$obj(...) 當函數呼叫任意PHP 5.3+,支援可呼叫物件
__set_state($array)var_export($obj)新實例static、PHP 5.1+
__debugInfo()var_dump($obj)arrayPHP 5.6+,控制除錯輸出

範例:可呼叫的服務類

class Logger {
    public function __invoke($level, $message) {
        $time = date('Y-m-d H:i:s');
        error_log("[{$time}] [{$level}] {$message}");
    }
}
$log = new Logger();
$log('INFO', 'Application started'); // 相當於 $log->__invoke(...)

序列化控制

方法觸發回傳用途
__sleep()serialize($obj)array (屬性名列表)排除資源連線、暫存資料
__wakeup()unserialize($str)void重建連線、初始化暫存
__serialize()serialize($obj) (PHP 7.4+)array取代 __sleep,更精確
__unserialize()unserialize($str) (PHP 7.4+)void取代 __wakeup,配合 __serialize

範例:排除 PDO 連線

class Repository {
    private $pdo;
    private $cache = [];
    
    public function __sleep() {
        return ['cache']; // 僅序列化快取
    }
    
    public function __wakeup() {
        $this->pdo = new PDO(/* 連線參數 */);
    }
}

方法多載(Method Overloading)

方法觸發參數回傳
__call($name, $args)呼叫不可存取實例方法方法名、參數陣列任意
__callStatic($name, $args)呼叫不可存取靜態方法方法名、參數陣列任意

實戰:委派給內部物件

class Service {
    private $driver;
    
    public function __construct(DriverInterface $driver) {
        $this->driver = $driver;
    }
    
    public function __call($method, $args) {
        if (method_exists($this->driver, $method)) {
            return $this->driver->$method(...$args);
        }
        throw new BadMethodCallException("Method {$method} not found");
    }
}

已棄用:__autoload()

PHP 7.2 棄用、8.0 移除。請改用 spl_autoload_register() 或 Composer PSR-4 自動載入。

速查總表

分類方法PHP 版本
生命週期__construct5.0
__destruct5.0
__clone5.0
屬性多載__get5.0
__set5.0
__isset5.0
__unset5.0
轉換/表示__toString5.0
__invoke5.3
__set_state5.1
__debugInfo5.6
__serialize7.4
序列化__sleep5.0
__wakeup5.0
方法多載__call5.0
__callStatic5.3

善用魔術方法能編寫出極具表達力的 DSL、動態 Proxy、不可變值物件等進階模式,但濫用會降低程式碼可讀性,請在架構層級謹慎決策。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved