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

PHP 魔術常數與魔術方法完整圖解:從 __LINE__ 到 __serialize()

     編輯:PHP 相關知識

PHP 提供九個魔術常數 (值隨程式碼位置改變) 與十七個魔術方法 (特定生命週期自動觸發)。掌握它們能大幅簡化除錯、序列化、物件行為控制等常見任務。本文分類整理、附實際輸出範例、說明常見誤區與最佳實踐。

一、九大魔術常數 (編譯時解析)

常數說明範例輸出版本
__LINE__當前行號15所有
__FILE__完整絕對路徑 (已解析符號連結)/var/www/html/index.php4.0.2+
__DIR__所在目錄 (等同 dirname(__FILE__))/var/www/html5.3.0+
__FUNCTION__函式名稱 (區分大小寫)myFunc4.3.0+
__CLASS__類別名稱 (含命名空間,區分大小寫)App\Models\User4.3.0+
__TRAIT__Trait 名稱 (含命名空間)App\Traits\Loggable5.4.0+
__METHOD__類別方法名稱 (含類別名)App\Models\User::getName5.0.0+
__NAMESPACE__當前命名空間名稱App\Models5.3.0+
::class類別完全限定名 (非魔術常數,但常搭配使用)App\Models\User5.5.0+

實際輸出範例

<?php
namespace App\Controllers;

class Demo {
    public function test() {
        echo "__LINE__: " . __LINE__ . "\n";        // 5
        echo "__FILE__: " . __FILE__ . "\n";        // /path/to/Demo.php
        echo "__DIR__: " . __DIR__ . "\n";          // /path/to
        echo "__FUNCTION__: " . __FUNCTION__ . "\n"; // test
        echo "__CLASS__: " . __CLASS__ . "\n";       // App\Controllers\Demo
        echo "__METHOD__: " . __METHOD__ . "\n";     // App\Controllers\Demo::test
        echo "__NAMESPACE__: " . __NAMESPACE__ . "\n"; // App\Controllers
    }
}
(new Demo())->test();

二、十七大魔術方法 (生命週期鉤子)

1. 建構/解構/複製

方法觸發時機典型用途回傳值
__construct(...$args)new Class()初始化屬性、注入依賴無 (不可回傳值)
__destruct()物件被銷毀 (引用計數歸零、腳本結束)釋放資源、關閉連線、記錄日誌無
__clone()clone $obj深層複製屬性、重新初始化資源 ID無

2. 屬性存取攔截

方法觸發條件參數典型用途
__get($name)讀取不可見屬性 (不存在、protected/private)屬性名動態屬性、延遲載入、代理模式
__set($name, $value)寫入不可見屬性屬性名、值驗證、轉換、觸發事件
__isset($name)isset($obj->prop) 或 empty()屬性名定義「存在」邏輯
__unset($name)unset($obj->prop)屬性名清理相關資源

3. 方法呼叫攔截

方法觸發條件參數典型用途
__call($name, $args)實例呼叫不可見方法方法名、參數陣列動態方法、委派、Fluent API
__callStatic($name, $args)靜態呼叫不可見方法方法名、參數陣列工廠方法、查詢建構器

4. 字串/序列化/匯出

方法觸發條件回傳值要求典型用途
__toString()echo $obj, (string)$obj, printf('%s', $obj)必須回傳 string物件輸出格式化、ID 顯示
__invoke(...$args)$obj() 當作函式呼叫任意可呼叫物件、策略模式、中介軟體
__set_state($props)var_export($obj)回傳新物件實例匯出可執行程式碼重建物件
__serialize()serialize($obj) (PHP 7.4+)回傳關聯陣列 [prop => val]自訂序列化資料、排除敏感欄位
__unserialize($data)unserialize($str) (PHP 7.4+)無 (還原 $this)對應 __serialize 還原
__sleep()serialize($obj) (舊版)回傳屬性名陣列選擇性序列化、關閉資源
__wakeup()unserialize($str) (舊版)無 (重新初始化)重新建立連線、驗證資料完整性

5. 自動載入 (已棄用)

// PHP 7.2 棄用,8.0 移除,請改用 spl_autoload_register()
function __autoload($class) { /* ... */ }

三、常見誤區與最佳實踐

  1. __toString 必須回傳字串:回傳非字串會拋出 Error (PHP 7.4+) 或 E_RECOVERABLE_ERROR。
  2. __sleep 回傳陣列決定序列化哪些屬性:若省略父類屬性,父類 __sleep 不會自動被呼叫,需手動 array_merge(parent::__sleep(), [...])。
  3. __serialize/__unserialize 取代 __sleep/__wakeup:新版更直觀、支援類型提示、不依賴屬性可見性。
  4. __call/__callStatic 僅攔截「不可見」方法:public 方法不會觸發。
  5. __destruct 例外無法被捕捉:在解構子中避免拋出例外,改用 error_log()。
  6. 魔術常數在 include/require 中行為不同:__FILE__ 為被包含檔案路徑,__DIR__ 同理。

四、實戰範例:動態屬性代理類

class Entity
{
    private array $data = [];
    private array $original = [];

    public function __construct(array $data = []) {
        $this->data = $data;
        $this->original = $data;
    }

    public function __get(string $name) {
        return $this->data[$name] ?? null;
    }

    public function __set(string $name, $value): void {
        $this->data[$name] = $value;
    }

    public function __isset(string $name): bool {
        return isset($this->data[$name]);
    }

    public function __unset(string $name): void {
        unset($this->data[$name]);
    }

    public function isDirty(): bool {
        return $this->data !== $this->original;
    }

    public function getChanges(): array {
        return array_diff_assoc($this->data, $this->original);
    }

    public function __serialize(): array {
        return ['data' => $this->data, 'original' => $this->original];
    }

    public function __unserialize(array $data): void {
        $this->data = $data['data'];
        $this->original = $data['original'];
    }
}

// 使用
$user = new Entity(['name' => 'Alice']);
$user->email = 'alice@example.com'; // __set
echo $user->name; // __get -> Alice
serialize($user); // __serialize

魔術常數提供「程式碼感知」能力,魔術方法提供「物件行為擴展」能力。善用它們能讓框架級程式碼更優雅、業務邏輯更聚焦,但濫用會導致隱式行為難以追蹤,建議在基礎設施層 (Model 基類、DTO、Repository) 使用,業務層盡量顯式。

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