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

PHP 魔術方法 __get() 與 __set() 詳細解析:不可訪問屬性的攔截器

     編輯:PHP 綜合知識

官方定義回顧

  • __set($name, $value):向不可訪問屬性賦值時觸發。
  • __get($name):讀取不可訪問屬性時觸發。

「不可訪問」包含兩種情況:

  1. 訪問權限受限:private、protected 屬性在類外部訪問。
  2. 屬性不存在:未聲明或未初始化的動態屬性。

代碼驗證核心行為

<?php
error_reporting(E_ALL);
class Stu {
    private $a;
    private $b = 0;
    public $c;
    public $d = 0;

    public function __get($name) {
        echo "__get($name) called\n";
        return 123;
    }
    public function __set($name, $value) {
        echo "__set($name, $value) called\n";
    }
}
$s = new Stu();
var_dump($s->a); // 輸出 123,觸發 __get(private)
var_dump($s->b); // 輸出 123,觸發 __get(private)
var_dump($s->c); // 輸出 NULL,不觸發 __get(public 存在)
var_dump($s->d); // 輸出 0,不觸發 __get(public 已初始化)
var_dump($s->e); // 輸出 123,觸發 __get(不存在)

$s->a = 3; // 觸發 __set(private)
$s->c = 3; // 不觸發 __set(public 可直接寫入)
$s->f = 3; // 觸發 __set(不存在)
?>

行為總結表

操作屬性狀態是否觸發魔術方法備註
讀取private/protected是 (__get)外部不可直接讀
讀取public 且已初始化否直接返回值
讀取public 未初始化 / 不存在是 (__get)視為不可訪問
寫入private/protected是 (__set)外部不可直接寫
寫入public否直接賦值
寫入不存在是 (__set)動態屬性攔截

常見應用場景

  1. 屬性代理/懶加載:__get 中從緩存/數據庫按需載入數據。
  2. 數據驗證/過濾:__set 統一驗證、轉義、類型轉換。
  3. 只讀屬性:__set 拋出異常或靜默忽略。
  4. 動態屬性映射:將未定義屬性映射到內部陣列 $this->data[$name]。

進階:配合 __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) 能正確作用於動態屬性。

最佳實踐與陷阱

  • 避免無限遞歸:__get 內部讀取同名屬性會再次觸發,需操作內部儲存陣列 $this->data。
  • 性能考量:魔術方法比直接訪問慢,高頻熱點屬性建議顯式聲明 public 或提供 getXxx()/setXxx()。
  • IDE 支持:動態屬性無法被靜態分析,建議在類文檔添加 @property 註解。
  • 序列化影響:__sleep/__wakeup 需手動處理動態屬性。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved