PHP 8 新功能 Named arguments Constructor property promotion Nullsafe operator Just-In-Time compilation JIT
PHP

PHP 8 的新功能與優化:Named arguments,Constructor property promotion,Nullsafe operator,Just-In-Time (JIT) compilation

PHP 8 正式版在去年 (2020年) 11月釋出,PHP 7 的最後一個版本就是 PHP 7.4 了。PHP 8 推出了一些新功能、新寫法,修正了 PHP 語言長期的字串 / 數字比較問題,推出了 Just-In-Time (JIT) compilation,加快執行效率。本篇文章就照著官方文件的順序,來走一遍 PHP 8.0 的新功能。

https://www.php.net/releases/8.0/en.php

Named Arguments 命名參數

舉例來講,function htmlspecialchars 的 prototype

function htmlspecialchars(
    string $string,
    int $flags = ENT_COMPAT,
    string $encoding = null,
    bool $double_encode = true
)

如果只是要指定其中一個參數 double_encode,其他用預設值,PHP 8 可以這樣寫

htmlspecialchars($string, double_encode: false);

注意 flags, encoding 都不用輸入。官方文件並提到,使用 Named Arguments 時參數不需要依照順序。

另外,如上方範例,Named Arguments 可以跟傳統輸入參數的方式混用。可以混用又 Named Arguments 沒有順序限制,會不會造成 ambiguous。如果用 coding convention 去限制,又會造成開發上的成本。larry 個人是對這個新功能持保留態度。

Constructor property promotion

在 PHP 8,constructor arguments 可以直接宣告成 class 的屬性。如下範例,注意 constructor arguments 前直接加了 public modifier。

class Point {
  public function __construct(
    public float $x = 0.0,
    public float $y = 0.0,
    public float $z = 0.0,
  ) {}
}

這樣 x, y, z 就直接宣告成 class 的屬性,不需要另外宣告

class Point {
  // 不需要
  public float $x;
  public float $y;
  public float $z;
  ...
}

這樣的確簡化了很多程式碼,但少了明文定義 class 的屬性。這樣真的不會造成混淆嗎?而且一樣,如果用 coding convention 去限制,又會造成開發上的成本。對這個新功能我還是持保留態度。

Match expression (match 表達式)

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

match 表達式是 PHP 8 新出的。與 switch 判斷式比較,match 表達式會直接 return 數值,並用 strict comparison 做輸入/選項比較。相對的,switch 判斷式是 loose comparison。所以如果用 switch,輸入 8.0,會先找到字串的 ‘8.0’。

寫法跟應用上 larry 還是不太習慣。match 大括號裡的東西比較像 array 的寫法,卻用大括號包住。應用上也有點 array 的味道,那直接使用 array 相關 function 反而還清楚一點。

Nullsafe operator

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

如果 $session 有值,return $session->user。如果 $session->user 有值,return $session->user->getAddress(),依此類推。從左到右,每一個問號會評估一次是否為 null,如果不為 null,繼續往右走。如果為 null,中斷在為 null 的部分,並 return null。

讀者可以評估一下上面 sample code,如果以 if else 來寫,或以三元運算子來寫,會有多少程式碼。用 nullsafe operator 除了簡潔以外,語意上也清楚。這個新功能 larry 會考慮使用。

Saner string to number comparisons 較健康的字串 / 數字比較

0 == 'foobar';
// PHP 7 和 PHP 7 以前會 return true
// PHP 8 會 return false

在 PHP 7 和 PHP 7 以前,上面 sample code 比較的方式是字串 “foobar” 先嘗試 cast 成數字,發現沒辦法 cast,所以 cast 成 0,所以上面比較式 return true。這部分是 PHP 語言長期的一個缺陷,尤其當使用 in_array, switch 等包含 implicit comparison 時,最好自己先判斷會不會有字串 / 數字比較的情況,不然 implicit comparison 判斷可能有誤。

PHP 8 修正了這個錯誤,除了將字串 cast 成數字外,也會將要比較的數字 cast 成字串,字串對字串比較。也就是比之前多了一個比較條件。

Just-In-Time (JIT) compilation

PHP 是直譯式語言 (interpreted language),要先裝好 PHP 套件,執行時 PHP code 會在 PHP 套件的環境裡,也可以說是透過 PHP 套件,不用編譯,直接執行。

PHP 8 推出的 Just-In-Time (JIT) compilation,會在執行期間,自動將某些 code 編譯,主要是 JIT 引擎分析會頻繁執行的 code,進行編譯,以達成效能的最大化。

原本 PHP 要透過一個 Zend virtual machine 與 CPU 溝通。有了 JIT compiler,部分程式碼會被編譯,快取在記憶體裡。當第二次執行該段 code,又編譯碼的快取還在的話,就會繞過 Zend virtual machine,直接執行編譯碼與 CPU 溝通。

PHP 8 的 JIT compiler 有兩種:Tracing JIT 與 Function JIT。Function JIT 會編譯整個 PHP functions,但不會去分析程式碼結構。Tracing JIT 則會去找到這些重複又頻繁執行的 code,進行編譯。Tracing JIT 因為編譯的總量少,能加快編譯的速度 (節省主機資源),並在有限的記憶體 buffer,可以快取對整體效能最有幫助的編譯碼。

結論

PHP 8 大部份新寫法類型的功能,larry 是持保留態度,感覺對開發上沒有實質的幫助。PHP 8 修正了 PHP 語言長期的字串 / 數字比較問題,這件事需要知道一下。JIT 的部分也要知道,如果使用 PHP 8,JIT 的部分一定要正確 configure,開啟使用。

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。