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

PHP 5+ 魔術方法完整指南:從 __construct 到 __callStatic 的 11 大核心方法

     編輯:PHP 相關知識

前言

PHP 5 引入魔術方法,以雙底線 __ 開頭命名,在特定生命週期或事件自動觸發。善用它們可實現屬性存取攔截、自動載入、物件序列化、函式式呼叫等進階功能。本文系統整理 11 個核心魔術方法的觸發時機、參數與實戰範例。

1. 屬性存取攔截:__get / __set

觸發條件

  • 存取未定義屬性(含 protected/private 不可見屬性)

class Entity {
    private $data = [];
    public function __get($name) {
        return isset($this->data[$name]) ? $this->data[$name] : null;
    }
    public function __set($name, $value) {
        $this->data[$name] = $value;
    }
}
$e = new Entity();
$e->title = 'Hello';  // 觸發 __set
echo $e->title;       // 觸發 __get

2. isset/unset 攔截:__isset / __unset


public function __isset($name) {
    return isset($this->data[$name]);
}
public function __unset($name) {
    unset($this->data[$name]);
}

isset($obj->prop)、unset($obj->prop) 觸發,同樣適用於不可見屬性。

3. 方法呼叫攔截:__call / __callStatic

__call(實例方法)


public function __call($method, $args) {
    if ($method === 'sayHello') {
        return "Hello, {$args[0]}!";
    }
    throw new BadMethodCallException("Method $method not found");
}
$obj->sayHello('World'); // "Hello, World!"

__callStatic(靜態方法,PHP 5.3+)


public static function __callStatic($method, $args) {
    // 靜態代理、工廠模式常用
}
ClassName::staticMethod(); // 觸發 __callStatic

注意:兩者必須宣告為 public,__callStatic 另需 static 關鍵字。

4. 自動載入:__autoload / spl_autoload_register

__autoload(單一全域,已不推薦)


function __autoload($class) {
    include "classes/$class.php";
}

缺點:只能定義一個、例外無法被 catch 捕獲(會致命錯誤)。

spl_autoload_register(推薦,支援多載入器)


class Loader {
    public static function autoload($class) {
        $file = __DIR__ . "/src/$class.php";
        if (file_exists($file)) require $file;
    }
}
spl_autoload_register(['Loader', 'autoload']);
// 亦可用匿名函數
spl_autoload_register(function($class) {
    // PSR-4 對應邏輯
});

5. 生命週期:__construct / __destruct

方法觸發時機常見用途
__construct物件實例化時初始化屬性、注入依賴、建立連線
__destruct物件銷毀前(記憶體釋放前)關閉連線、釋放資源、寫入日誌

class Database {
    private $pdo;
    public function __construct($dsn) {
        $this->pdo = new PDO($dsn);
    }
    public function __destruct() {
        $this->pdo = null; // 關閉連線
    }
}

銷毀時機:函數內區域變數在 return 時;全域變數在腳本結束時;手動 unset($obj) 或賦值 null 時。

6. 物件複製:__clone

PHP 5 物件預設為參考指派,clone 關鍵字建立淺拷貝,觸發 __clone 可執行深拷貝邏輯。


class User {
    public $name;
    public $address; // 物件
    public function __clone() {
        $this->address = clone $this->address; // 深拷貝關聯物件
    }
}
$u2 = clone $u1;

7. 字串轉換:__toString


public function __toString() {
    return "User: {$this->name}";
}
echo $user; // 自動觸發
  • 必須回傳 string,否則拋出 E_RECOVERABLE_ERROR(PHP 5.2+)
  • PHP 5.2 前僅 echo/print 觸發;5.2+ 所有字串語境(如 printf('%s', $obj))均觸發

8. 序列化控制:__sleep / __wakeup


public function __sleep() {
    $this->db->close(); // 關閉連線
    return ['name', 'email']; // 僅序列化指定屬性
}
public function __wakeup() {
    $this->db = new Database(); // 重建連線
}
  • __sleep:serialize() 前調用,回傳需序列化屬性名陣列
  • __wakeup:unserialize() 後調用,重建資源

9. var_export 支援:__set_state(PHP 5.1+)


public static function __set_state(array $props) {
    $obj = new self();
    foreach ($props as $k => $v) $obj->$k = $v;
    return $obj;
}

var_export($obj, true) 產生的程式碼可直接 eval() 還原物件。

10. 函式式呼叫:__invoke(PHP 5.3+)


class CallableClass {
    public function __invoke($x, $y) {
        return $x + $y;
    }
}
$fn = new CallableClass();
echo $fn(2, 3); // 5,如同呼叫函數

使物件可當作 callable 傳遞,配合 array_map、Closure::fromCallable 等極為強大。

11. 靜態方法攔截:__callStatic(PHP 5.3+)

詳見第 3 節,常用於靜態工廠、ActiveRecord 風格查詢:


User::findByEmail('test@example.com'); // 觸發 __callStatic

可見性規則總結

  • 所有魔術方法必須宣告為 public
  • __callStatic 必須加 static
  • __construct/__destruct/__clone 等不可被繼承覆寫為非 public

小結

魔術方法是 PHP 物件模型的擴展點,核心場景包括:

  1. 屬性/方法動態代理(__get/__set/__call)
  2. 生命週期管理(__construct/__destruct/__clone)
  3. 序列化與還原(__sleep/__wakeup/__set_state)
  4. 型別轉換與呼叫(__toString/__invoke)
  5. 自動載入(spl_autoload_register 取代 __autoload)

合理使用可大幅提升程式碼彈性,濫用則會降低可讀性,建議在框架核心、ORM、代理模式等場景採用。

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