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

PHP 魔術方法 __get() 與 __set() 完整用法詳解

     編輯:PHP 綜合知識

PHP 物件導向中的屬性存取魔術方法

在 PHP 物件導向程式設計中,良好的封裝性要求將類別屬性宣告為 private。然而,頻繁的屬性讀寫操作若都透過個別的 getter/setter 方法會顯得繁瑣。PHP 5 引入了兩個魔術方法 __get() 與 __set(),讓我們能以類似 JavaBean 的方式統一處理私有屬性的存取,且無需為每個欄位單獨撰寫存取器。

核心概念

  • __get($name):當嘗試讀取不可存取(private/protected 或不存在)的屬性時自動觸發。參數 $name 為屬性名稱,需回傳對應的值。
  • __set($name, $value):當嘗試寫入不可存取的屬性時自動觸發。參數分別為屬性名稱與指定值,無回傳值。

這兩個方法並非預設存在,必須在類別中手動定義(如同 __construct())。只有當屬性被封裝為 private/protected 時,直接存取才會觸發這些魔術方法;若屬性為 public,則不會被呼叫。

基本實作範例

class Person {
    private $name;
    private $sex;
    private $age;

    public function __set($property_name, $value) {
        echo "自動呼叫 __set() 設定私有屬性:$property_name
"; $this->$property_name = $value; } public function __get($property_name) { echo "自動呼叫 __get() 讀取私有屬性:$property_name
"; if (isset($this->$property_name)) { return $this->$property_name; } return null; } } $p1 = new Person(); $p1->name = "張三"; // 觸發 __set() $p1->sex = "男"; $p1->age = 20; echo "姓名:" . $p1->name . "
"; // 觸發 __get() echo "性別:" . $p1->sex . "
"; echo "年齡:" . $p1->age . "
";

進階應用:加入驗證邏輯

在 __set() 中可加入資料驗證,確保屬性值符合業務規則:

public function __set($property_name, $value) {
    switch ($property_name) {
        case 'age':
            if (!is_int($value) || $value < 0 || $value > 150) {
                throw new InvalidArgumentException("年齡必須為 0-150 之間的整數");
            }
            $this->$property_name = $value;
            break;
        case 'name':
            if (empty(trim($value))) {
                throw new InvalidArgumentException("姓名不可為空");
            }
            $this->$property_name = trim($value);
            break;
        default:
            $this->$property_name = $value;
    }
}

執行結果示意

自動呼叫 __set() 設定私有屬性:name
自動呼叫 __set() 設定私有屬性:sex
自動呼叫 __set() 設定私有屬性:age
自動呼叫 __get() 讀取私有屬性:name
姓名:張三
自動呼叫 __get() 讀取私有屬性:sex
性別:男
自動呼叫 __get() 讀取私有屬性:age
年齡:20

注意事項與最佳實踐

  1. 效能考量:魔術方法會增加方法呼叫開銷,高頻存取場景建議改用明確的 getter/setter。
  2. 除錯困難:IDE 難以自動完成與靜態分析魔術屬性,建議搭配 @property 註解。
  3. 遞迴風險:在魔術方法內部存取同名屬性會導致無限遞迴,務必使用 $this->data[$name] 等內部儲存陣列。
  4. 唯讀屬性:若不實作 __set(),屬性即為唯讀。

改良版實作:使用內部陣列儲存

class Entity {
    private $data = [];
    private $allowed = ['name', 'email', 'age'];

    public function __set($name, $value) {
        if (!in_array($name, $this->allowed)) {
            throw new Exception("不允許設定屬性:$name");
        }
        $this->data[$name] = $value;
    }

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

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

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

掌握 __get()/__set() 能讓 PHP 類別兼具封裝性與靈活存取,是進階物件導向開發的關鍵技巧之一。

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