2024年的PHP 8.4:Property Hooks 帶來的全新體驗

更新 發佈閱讀 16 分鐘

「嘿,你有聽說 PHP 8.4 的新特性了嗎?」同事David一臉興奮地問我。

我轉過頭,手上還拿著極韻白,「你是說 Property Hooks?就是那個讓我們在存取屬性時可以加上 get/set 邏輯的東西嗎?」

「對啊!」David笑得合不攏嘴,「終於不用再為了每個小驗證寫滿 GetterSetter 方法了,也不用 __get() __set() 那麼大刀闊斧的攔截全部undefined屬性。」

如果你曾經為了在程式中控制屬性存取邏輯而煩惱不已,又或者討厭為每個屬性寫一堆 getXxx()、setXxx(),那麼 PHP 8.4 的 Property Hooks 絕對是你想要的。這個新特性讓我們可以直接在屬性宣告中對「存取行為」加入特定邏輯,同時兼顧程式碼的乾淨度與可讀性。

接下來,我們用最直觀、易懂的方式,帶你體驗 Property Hooks 的世界!

先別急,我們會先從「傳統的Getter/Setter 寫法」開始比較,一步步看出有了 Property Hooks 後的差異性。

沒有 Property Hooks 時的傳統寫法

在 PHP 8.4 之前,若你想在屬性賦值或讀取時做點小動作(例如:寫入時驗證、讀取時格式化),往往需要這樣的模式:

class User {

private string $name;

public function __construct(string $name) {

$this->setName($name);
}

public function getName(): string {

// 讀取時可能要處理一些邏輯

// 例如轉成大寫
return strtoupper($this->name);
}

public function setName(string $value): void {

// 寫入前先驗證
if (strlen($value) < 2) {

throw new InvalidArgumentException("Name is too short!");
}

$this->name = $value;
}
}

$user = new User("Tom");
echo $user->getName(); // "TOM"
$user->setName("A"); // 丟出例外

這段程式碼有什麼問題?

  • 我們為了控制屬性的存取,增加了 Getter/Setter 方法,程式碼變長了。
  • 寫的時候還好,日後維護或增加屬性時可能很煩,一個屬性兩個方法,多了 10 個屬性,就是 20 個方法。

再看看另一種「魔術方法」的做法( __get() 與 __set()):

class User {

private string $name;

public function __construct(string $name) {

$this->name = $name;
}

public function __get($prop) {

if ($prop === 'name') {

// 路徑一:讀取 name
return strtoupper($this->name);
}

throw new Exception("Property $prop not found");
}

public function __set($prop, $value) {

if ($prop === 'name') {

if (strlen($value) < 2) {

throw new InvalidArgumentException("Name too short!");
}

$this->name = $value;

return;
}

throw new Exception("Property $prop not found");
}
}

這魔術方法的寫法,雖然不需要每個屬性分別寫 getXxx() 和 setXxx(),但實務上卻是大砲打小鳥。

它攔截所有未定義的屬性存取,是個「一刀切」的做法,不僅難以維護,也讓 IDE 或靜態分析工具難以推斷屬性實際存在與否。

有了 Property Hooks 後的世界

現在,看看 PHP 8.4 的 Property Hooks:

class User {

public string $name {

get => strtoupper($this->name); // 讀取時自動轉成大寫

set (string $value) {

if (strlen($value) < 2) {

throw new InvalidArgumentException("Name too short!");
}

$this->name = $value;
}
}

public function __construct(string $name) {

$this->name = $name; // 寫入時會觸發 set 掛鉤
}
}

$user = new User("Tom");
echo $user->name; // 読取時觸發 get 掛鉤,輸出 "TOM"
$user->name = "A"; // 寫入觸發 set 掛鉤,因長度不足拋出例外

在這裡,我們直接在屬性宣告中利用 { } 區塊,定義 get 與 set 的邏輯。

神奇之處在於:

  • 讀取 $user→name 時,自動走 get 區塊。
  • 寫入 $user→name = … 時,自動走 set 區塊。
  • 這個屬性本身就像帶有內建控制邏輯的「智慧屬性」。

看起來是不是清爽許多?

實際案例對比:沒有 Property Hooks vs. 有 Property Hooks

範例一:基本驗證

傳統做法:

class Product {

private int $price;

public function __construct(int $price) {

$this->setPrice($price);
}

public function setPrice(int $price) {

if ($price < 0) {

throw new InvalidArgumentException("Price can't be negative!");
}

$this->price = $price;
}

public function getPrice(): int {

return $this->price;
}
}

$product = new Product(100);
echo $product->getPrice(); // 100
$product->setPrice(-10); // Exception

使用 Property Hooks:

class Product {

public int $price {

set (int $value) {

if ($value < 0) {

throw new InvalidArgumentException("Price can't be negative!");
}

$this->price = $value;
}

// 未實作 get, 預設讀取直接取得 backing value
// 如果要在讀取時做點事,也可加上 get => ...;
}

public function __construct(int $price) {

$this->price = $price; // 觸發 set 區塊
}
}

$product = new Product(100);
echo $product->price; // 100 (直接讀取,未實作 get,則為預設讀取行為)
$product->price = -10; // Exception

程式碼明顯更精簡。

範例二:虛擬屬性 (Virtual Property)

Property Hooks 也能產生「虛擬屬性」,就像前端的 computed property。

所謂虛擬屬性,就是該屬性並沒有真正在物件中存儲資料,而是動態取得或寫入時處理其他屬性。

傳統作法 (無 Hooks):

class User {

private string $firstName;

private string $lastName;

public function __construct(string $first, string $last) {

$this->firstName = $first;
$this->lastName = $last;
}

public function getFullName(): string {

return $this->firstName.' '.$this->lastName;
}

public function setFullName(string $value): void {

[$f, $l] = explode(' ', $value, 2);

$this->firstName = $f;
$this->lastName = $l;
}
}

$user = new User("John", "Doe");
echo $user->getFullName(); // John Doe
$user->setFullName("Jane Smith");
echo $user->getFullName(); // Jane Smith

有 Hooks 之後:

class User {

private string $firstName;

private string $lastName;

public string $fullName {

get => $this->firstName.' '.$this->lastName;

set {

[$f, $l] = explode(' ', $value, 2);

$this->firstName = $f;
$this->lastName = $l;
}
}

public function __construct(string $first, string $last) {

$this->firstName = $first;
$this->lastName = $last;
}
}

$user = new User("John", "Doe");
echo $user->fullName; // John Doe (透過 get hooks 動態取得)
$user->fullName = "Jane Smith"; // set hooks 動態拆解名稱
echo $user->fullName; // Jane Smith

完全不需要額外的方法名稱,直接用 $user→fullName,存取像是正常屬性,卻暗藏邏輯!

Property Hooks 的其他優勢

  • 介面與抽象類別支援:PHP 8.4 也允許在介面或抽象類別中定義需要 get 或 set 的屬性契約,讓物件行為更一致。
  • 明確性:跟 __get() __set() 相比,Property Hooks 只對定義的屬性生效,不是大範圍的「隱形陷阱」。
  • 工具友善:靜態分析工具與 IDE 能更輕鬆解析屬性行為,因為掛鉤是明確定義在屬性上,而非動態攔截。

實務建議

使用 Property Hooks 不代表要棄守 Getter/Setter。在特定場合,傳統 Getter/Setter 仍有存在價值(例如需相容舊有程式碼或某些框架習慣)。但在新的專案中,如果你想讓屬性操作更自然、程式碼更精簡,同時又能確保寫入與讀取的規則一致,那 Property Hooks 絕對是新寵兒。

要注意的是,雖然看起來很方便,但別因此在每個屬性上都加一堆複雜邏輯。

保持適度、保持簡單,才是維護上的王道。

最後

Property Hooks 是 PHP 8.4 的亮點之一。它解決了以往實作屬性控制的繁瑣,讓程式碼更直觀。從前我們得寫好多 Getter/Setter,或使用魔術方法來處理存取邏輯;現在,我們可以直觀地將邏輯和屬性綁在一起,就像給屬性裝上小小的「智慧晶片」。

希望這篇文章透過大量的程式碼對比、淺顯易懂的解說,讓你對 Property Hooks 有更清晰的認識。下次在寫 PHP 8.4 的程式時,不妨試試看這項特性,相信你會愛上這種「所見即所得」的程式碼體驗!

加油,繼續探索 PHP 的新可能!

參考資料

https://wiki.php.net/rfc/property-hooks

https://laravel-news.com/php-8-4-0

https://laravel-news.com/php-property-hooks


留言
avatar-img
留言分享你的想法!
avatar-img
詹姆士的軟體易開罐
27會員
88內容數
這是一系列以軟體開發為主題的輕鬆分享,內容涵蓋了技術選擇、開發經驗、實戰應用等多方面的議題。無論是如何在眾多框架中做出選擇,還是如何應對技術轉移的挑戰,這裡有幽默、有趣的對話風格,將複雜的技術問題轉化為易懂的故事。
2025/04/05
if寫得好,可以大大提高效率與可讀性。 Guard condition在函式起始先排除不合規輸入,能簡化結構、減少錯誤,使核心邏輯更聚焦並提高可維護性,也方便擴充與測試,在團隊協作和需求變動時,都能更快速應對。建議根據實際情況彈性運用,兼顧可讀性與維護成本。
Thumbnail
2025/04/05
if寫得好,可以大大提高效率與可讀性。 Guard condition在函式起始先排除不合規輸入,能簡化結構、減少錯誤,使核心邏輯更聚焦並提高可維護性,也方便擴充與測試,在團隊協作和需求變動時,都能更快速應對。建議根據實際情況彈性運用,兼顧可讀性與維護成本。
Thumbnail
2025/01/24
還記得我剛開始負責專案時,幾乎沒有人在意測試,改了程式碼就直接上線,結果小錯不斷、大災難頻傳。那種不知道哪裡會冒出 bug 的焦慮感,讓人每天都忙到焦頭爛額,卻依舊無從掌握系統品質。走過這段混亂的過程後,我才真正體會「為什麼需要測試」,也更明白「測試文化」並非只是技術細節。
Thumbnail
2025/01/24
還記得我剛開始負責專案時,幾乎沒有人在意測試,改了程式碼就直接上線,結果小錯不斷、大災難頻傳。那種不知道哪裡會冒出 bug 的焦慮感,讓人每天都忙到焦頭爛額,卻依舊無從掌握系統品質。走過這段混亂的過程後,我才真正體會「為什麼需要測試」,也更明白「測試文化」並非只是技術細節。
Thumbnail
2025/01/24
我想探討,從「個人測試」到「團隊測試策略」的思維轉換,強調測試不僅是個人的責任,更需要整個團隊的支持與參與。文章還提供了推動測試文化的具體建議,包括設定最小測試門檻、融入開發流程,以及如何克服常見的困境如進度壓力或技術債問題。
Thumbnail
2025/01/24
我想探討,從「個人測試」到「團隊測試策略」的思維轉換,強調測試不僅是個人的責任,更需要整個團隊的支持與參與。文章還提供了推動測試文化的具體建議,包括設定最小測試門檻、融入開發流程,以及如何克服常見的困境如進度壓力或技術債問題。
Thumbnail
看更多
你可能也想看
Thumbnail
透過蝦皮分潤計畫,輕鬆賺取零用金!本文分享5-6月實測心得,包含數據流程、實際收入、平臺優點及注意事項,並推薦高分潤商品,教你如何運用空閒時間創造被動收入。
Thumbnail
透過蝦皮分潤計畫,輕鬆賺取零用金!本文分享5-6月實測心得,包含數據流程、實際收入、平臺優點及注意事項,並推薦高分潤商品,教你如何運用空閒時間創造被動收入。
Thumbnail
單身的人有些會養寵物,而我養植物。畢竟寵物離世會傷心,植物沒養好再接再厲就好了~(笑)
Thumbnail
單身的人有些會養寵物,而我養植物。畢竟寵物離世會傷心,植物沒養好再接再厲就好了~(笑)
Thumbnail
不知你有沒有過這種經驗?衛生紙只剩最後一包、洗衣精倒不出來,或電池突然沒電。這次一次補貨,從電池、衛生紙到洗衣精,還順便分享使用心得。更棒的是,搭配蝦皮分潤計畫,愛用品不僅自己用得安心,分享給朋友還能賺回饋。立即使用推薦碼 X5Q344E,輕鬆上手,隨時隨地賺取分潤!
Thumbnail
不知你有沒有過這種經驗?衛生紙只剩最後一包、洗衣精倒不出來,或電池突然沒電。這次一次補貨,從電池、衛生紙到洗衣精,還順便分享使用心得。更棒的是,搭配蝦皮分潤計畫,愛用品不僅自己用得安心,分享給朋友還能賺回饋。立即使用推薦碼 X5Q344E,輕鬆上手,隨時隨地賺取分潤!
Thumbnail
身為一個典型的社畜,上班時間被會議、進度、KPI 塞得滿滿,下班後只想要找一個能夠安靜喘口氣的小角落。對我來說,畫畫就是那個屬於自己的小樹洞。無論是胡亂塗鴉,還是慢慢描繪喜歡的插畫人物,那個專注在筆觸和色彩的過程,就像在幫心靈按摩一樣,讓緊繃的神經慢慢鬆開。
Thumbnail
身為一個典型的社畜,上班時間被會議、進度、KPI 塞得滿滿,下班後只想要找一個能夠安靜喘口氣的小角落。對我來說,畫畫就是那個屬於自己的小樹洞。無論是胡亂塗鴉,還是慢慢描繪喜歡的插畫人物,那個專注在筆觸和色彩的過程,就像在幫心靈按摩一樣,讓緊繃的神經慢慢鬆開。
Thumbnail
這一章節旨在介紹 PHP 中的物件導向編程(OOP)概念。通過詳細講解類別、建構子、訪問修飾符(公開、私有、受保護)、繼承、多型、封裝、介面、抽象類別、靜態類別、列舉、委派、Lambda 表達式、泛型和反射等概念,使讀者能夠理解和應用這些 OOP 技術來編寫更具結構性和可維護性的 PHP 代碼。
Thumbnail
這一章節旨在介紹 PHP 中的物件導向編程(OOP)概念。通過詳細講解類別、建構子、訪問修飾符(公開、私有、受保護)、繼承、多型、封裝、介面、抽象類別、靜態類別、列舉、委派、Lambda 表達式、泛型和反射等概念,使讀者能夠理解和應用這些 OOP 技術來編寫更具結構性和可維護性的 PHP 代碼。
Thumbnail
在這一章中,我們探討了 PHP 中的函數,包括函數的基本結構、不同的函數定義方式(如函數聲明、函數表達式、箭頭函數和匿名函數)以及如何呼叫函數。我們還討論了函數的參數處理方式,包括單個參數、多個參數、預設參數值和剩餘參數。此外,我們還介紹了函數的返回值,包括返回單個值、返回物件和返回函數的情況。
Thumbnail
在這一章中,我們探討了 PHP 中的函數,包括函數的基本結構、不同的函數定義方式(如函數聲明、函數表達式、箭頭函數和匿名函數)以及如何呼叫函數。我們還討論了函數的參數處理方式,包括單個參數、多個參數、預設參數值和剩餘參數。此外,我們還介紹了函數的返回值,包括返回單個值、返回物件和返回函數的情況。
Thumbnail
在本節中,我們介紹了PHP的基本語法,包括如何在HTML中嵌入PHP代碼,PHP腳本的執行順序,以及多種註解方式。我們還學習了如何定義和使用變數,包括單個變數和多個變數的賦值方法。這些基礎知識將幫助你開始使用PHP進行Web開發。
Thumbnail
在本節中,我們介紹了PHP的基本語法,包括如何在HTML中嵌入PHP代碼,PHP腳本的執行順序,以及多種註解方式。我們還學習了如何定義和使用變數,包括單個變數和多個變數的賦值方法。這些基礎知識將幫助你開始使用PHP進行Web開發。
Thumbnail
本階段深掘PHP中類別與物件的應用,從基本定義到屬性與方法的運用,並特別著重於訪問控制和靜態成員的概念。學生將學會如何有效地利用公開、保護、私有屬性,以及如何在不實例化的情況下透過類別名稱直接訪問靜態屬性和方法,進一步鞏固物件導向程式設計的核心知識。
Thumbnail
本階段深掘PHP中類別與物件的應用,從基本定義到屬性與方法的運用,並特別著重於訪問控制和靜態成員的概念。學生將學會如何有效地利用公開、保護、私有屬性,以及如何在不實例化的情況下透過類別名稱直接訪問靜態屬性和方法,進一步鞏固物件導向程式設計的核心知識。
Thumbnail
PHP(全名為「PHP: Hypertext Preprocessor」)是一門開源的伺服器端程式語言,為動態網頁開發設計。閱讀本文將讓您瞭解PHP的特點、廣泛支援、易學性、資源豐富以及跨平臺性。
Thumbnail
PHP(全名為「PHP: Hypertext Preprocessor」)是一門開源的伺服器端程式語言,為動態網頁開發設計。閱讀本文將讓您瞭解PHP的特點、廣泛支援、易學性、資源豐富以及跨平臺性。
Thumbnail
C# 9.0 給 Unity 程式設計上帶來的便利
Thumbnail
C# 9.0 給 Unity 程式設計上帶來的便利
Thumbnail
一、存取修飾詞public / private / protected / internal 二、參數修飾詞ref / in / out >>>>>由於我們在寫程式時,會去宣告一些變數、常數相關識別詞,並且在class(類別)中會寫一些事情或動作讓程式去運行,然而這個概念就是去定義對於我們所寫的內容
Thumbnail
一、存取修飾詞public / private / protected / internal 二、參數修飾詞ref / in / out >>>>>由於我們在寫程式時,會去宣告一些變數、常數相關識別詞,並且在class(類別)中會寫一些事情或動作讓程式去運行,然而這個概念就是去定義對於我們所寫的內容
Thumbnail
介紹 在程式中你看到上面有一個中括號[] 就是特性,它自身沒有任何功能。 📷 特性attribute,和注釋有什麼區別 第一個感受 特性:中括號宣告 錯覺:每一個特性都可以帶來對應的功能 實際上添加後,編譯器會在元素內部產生IL,但是我們是沒辦法直接使用的,而且在metadata會有紀錄 📷
Thumbnail
介紹 在程式中你看到上面有一個中括號[] 就是特性,它自身沒有任何功能。 📷 特性attribute,和注釋有什麼區別 第一個感受 特性:中括號宣告 錯覺:每一個特性都可以帶來對應的功能 實際上添加後,編譯器會在元素內部產生IL,但是我們是沒辦法直接使用的,而且在metadata會有紀錄 📷
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News