PHP 8 正式釋出

千呼萬喚始出來!PHP 8.0 正式釋出!

今天七月的 LaravelConf Taiwan 2020 很榮幸成為開場講者,並且跟大家介紹 PHP 8 的新特性,事隔近半年後,總算推出了正式版本。(簡報參考)當時為了研究 JIT 原理,還跑去看組合語言,都覺得人生掉到谷底了,最後還是單純說明 JIT 流程和新特性為主。

以下再重新介紹幾個我覺得有趣的新特性,除了之前簡報有講的外,也有這半年後來被納入實作的。

Named arguments

官方例子非常經典:

Without Named arguments

htmlspecialchars($string, ENT_COMPAT | ENT_HTML401, 'UTF-8', false);

為了要特別給第四個參數是 false,則必須要把中間預設的參數都打上一次才能正常運作。

Using Named arguments

htmlspecialchars($string, double_encode: false);

有了 Named arguments 後,只要指定欄位名稱,即可傳入對應的值,而其他參數都會使用預設值。

類似的問題我也很常遇到,比方說 http_build_query()enc_type: PHP_QUERY_RFC3986json_decode()flags: JSON_THROW_ON_ERROR 等,用這個寫法就能清楚且方便地呼叫函式了。

但這功能也是雙面刃,因為參數可以不按順序方便地呼叫,這樣就有可能被當成 array 使用,並不斷的新增,最後這個 function 就會違反單一職責原則了。

Named arguments 詳情可參考 RFC

Match expression

這是一個很像 switch 語法的新語法:

Without Match expression

switch (8.0) {
case '8.0':
$result = "Oh no!";
break;
case 8.0:
$result = "This is what I expected";
break;
}
echo $result;
//> Oh no!

Using Match expression

echo match (8.0) {
'8.0' => "Oh no!",
8.0 => "This is what I expected",
};
//> This is what I expected

我個人認為這兩個語法最大的差異在於,match 比對到之後的行為,只能接受一行,但 switch 可以多行。這個關鍵差異將會影響到 switch 因為可以做很多事,所以很容易看到 switchswitchif else,這也是違反了單一職責原則。但 match 呢?它辦不到這點,使用它就必須 extract method。

Match expression 詳情可參考 RFC

Nullsafe operator

很多語言支援的寫法:

Nullsafe operator

$country =  null;

if ($session !== null) {
$user = $session->user;

if ($user !== null) {
$address = $user->getAddress();

if ($address !== null) {
$country = $address->country;
}
}
}

Using Nullsafe operator

$country = $session?->user?->getAddress()?->country;

這個寫法看起來很方便,但我目前想到的問題是,如果寫了一長串,就很有可能不知道在哪裡回 null。在資料處理上比較沒有問題,像 Laravel config('session.user.address.country') 若中間有個設定沒有,也是會直接回傳 null;程式執行流程上也許會怪怪的,比方說:

$country = $this->getUserService()?->getUser('foo')?->getAddress()?->country;

這個寫法下,如果回 null 就會有需要知道是哪一段回的,因為取 service 物件或取 user 物件失敗是兩個不同例外情境。

Nullsafe operator 詳情可參考 RFC