2022 年 12 月 8 號 PHP 8.2 發布了,這是 PHP 8 的第二次重大更新。從 2020 年開始,PHP 維持著每年更新一個次版本的進度,2020 年 11 月的 8.0,2021 年 11 月推出了 8.1。
作為最熱門的 PHP 框架,Laravel 9 及 10 都支援 PHP 8.2,如果還在使用 Laravel 8 及以前的版本,最多只支援到 8.1。
那我們話不多說,趕緊來看一下 PHP 8.2 有哪些重大的調整吧。
PHP 8.2 重大變動
Readonly classes 唯讀類別
PHP 8.1 的時候,PHP 推出了唯讀的屬性,而 8.2 則進化成唯讀類別。
一個類別被標記為唯讀時,它的所有屬性都會自動變成唯讀屬性 (Readonly Properties),而該類別將沒辦法動態地新增屬性。
readonly class Book
{
public string $title;
public function __construct(string $title)
{
$this->title = $title;
}
}
$book = new Book('Clean Code');
$book->title = 'Refactor';
會跳出錯誤訊息:
Cannot modify readonly property Book::$title
如果我們想要動態新增屬性也會被阻擋,例如我們動態的指派 author
到範例的 book
物件中:
$book->author = 'Robert C. Martin';
錯誤訊息:
Cannot create dynamic property Book::$author
DNF Types
DNF,全名 Disjunctive Normal Form,中文有點拗口我就不硬翻了。總之就是一種正規形式,用來將許多交集(AND)做聯集(OR),也就是 OR of ANDs
。
範例:
(A&B)|C
A|(B&C)|D
(A&B)|(C&D)
在 8.0 的時候,PHP 新增了聯集 Union Type,在 8.1 則新增了交集 Intersection Type。支援 DNF 後,在定義 PHP 的 function 參數型別,有了更多的彈性。
這項更新有助於我們在定義 function 時,更精準地宣告傳入的型別,或回傳的型別(return type)。
unit type 單值型別
PHP 8.2 可將 null
、false
、true
分別視為獨立的型別。
過去在 PHP 8.0 中,null
雖然可以作為 union type 的一部分,但卻沒辦法單獨存在。
至於 true
或 false
,過去只能使用 bool
來表示型別,但有些 function 雖然回傳型別宣告成 bool
, 但它其實並不回傳 true
, 只會回傳 false
,這種時候使用 bool
型別就不夠精準。
因此 PHP 8.2 允許 null
、false
、true
作為一個獨立的型別。這些型別因為只包含一種值,所以稱為 unit type
。
官網範例:
class Falsy
{
public function alwaysFalse(): false {}
public function alwaysTrue(): true {}
public function alwaysNull(): null {}
}
unit type 是 PHP 8.0 新增的功能,可以將兩個不同的類別聯合起來,作為一個參數的型別。例如function foo(string|int $boo)
,代表這個$boo
可以是字串也可以是數字。
複習 8.0 版的更新→這邊
在 traits 中的常數
一個實用且簡單的新功能,可以在 Trait 中宣告常數。
官網範例如下。不過要特別注意 Trait 的常數沒辦法直接被讀取,必須透過使用它的類別來做使用。
trait Foo
{
public const CONSTANT = 1;
}
class Bar
{
use Foo;
}
var_dump(Bar::CONSTANT); // 1
var_dump(Foo::CONSTANT); // Error
棄用動態屬性
PHP 中非常方便但也非常容易造成糞 Code 的動態屬性終於要被拿掉了。
在 8.2 中,使用動態屬性會有警告,根據 RFC 文件,可能在 PHP 9 會正式移除,屆時使用動態屬性則會拋出錯誤。但魔術方法 __get
及 __set
目前並不受這個改變影響。
class Book
{
public $title;
}
$book = new Book();
$book->author = 'Robert C. Martin';
// Deprecated notice
小結論
可以觀察到,相較於 8.0 及 8.1,PHP 8.2 的變動其實沒有很多,但也可以感受到 PHP 8.2 很努力在完善 PHP 的型別系統,讓 PHP 程式可以更穩健更可靠。
而棄用動態屬性也是一個很大的壯舉,可以終結動態屬性的濫用,讓 PHP 程式更不容易出錯,也更好除錯。
不過這讓我想到 Laravel,它在 Model 大量地使用了動態屬性,雖然 Laravel 都是透過魔術方法 __get
及 __set
來完成,雖然魔術方法並不在這次調整的影響範圍,但是不是也代表未來 Laravel 會改變設計的邏輯?這點值得觀察。
複習 8.1 更新了什麼→這邊