2024 年 PHP 日本研討會
已發布!
PHP 8.1 是 PHP 語言的主要更新。
它包含許多新功能,包括列舉、唯讀屬性、一等可呼叫語法、纖程、交集類型、效能改進等等。

列舉 RFC 文件

PHP < 8.1
類別 Status
{
const
DRAFT = 'draft';
const
PUBLISHED = 'published';
const
ARCHIVED = 'archived';
}
函式
acceptStatus(string $status) {...}
PHP 8.1
列舉 Status
{
case
Draft;
case
Published;
case
Archived;
}
函式
acceptStatus(Status $status) {...}
使用列舉類型取代一組常數,並直接獲得驗證功能。

唯讀屬性 RFC 文件

PHP < 8.1
類別 BlogData
{
private
Status $status;

public function
__construct(Status $status)
{
$this->status = $status;
}

public function
getStatus(): Status
{
return
$this->status;
}
}
PHP 8.1
類別 BlogData
{
public readonly
Status $status;

public function
__construct(Status $status)
{
$this->status = $status;
}
}

唯讀屬性在初始化後,也就是賦值後,就不能再被更改。
它們是建模值物件和資料傳輸物件的好方法。

一級可呼叫語法 RFC 文件

PHP < 8.1
$foo = [$this, 'foo'];

$fn = Closure::fromCallable('strlen');
PHP 8.1
$foo = $this->foo(...);

$fn = strlen(...);

現在可以取得任何函式的參考,這稱為一級可呼叫語法。

初始化器中的新功能 RFC

PHP < 8.1
類別 服務
{
私有
記錄器 $logger;

公開 函式
__construct(
?
記錄器 $logger = null,
) {
$this->logger = $logger ?? new 空記錄器();
}
}
PHP 8.1
類別 服務
{
私有
記錄器 $logger;

公開 函式
__construct(
記錄器 $logger = new 空記錄器(),
) {
$this->logger = $logger;
}
}

物件現在可以用作預設參數值、靜態變數和全域常數,以及屬性引數。

這實際上使得使用巢狀屬性成為可能。

PHP < 8.1
類別 使用者
{
/**
* @Assert\All({
* @Assert\NotNull,
* @Assert\Length(min=5)
* })
*/
公開 字串 $name = '';
}
PHP 8.1
類別 使用者
{
#[
\Assert\All(
new
\Assert\NotNull,
new
\Assert\Length(min: 5))
]
公開
字串 $name = '';
}

純交集類型 RFC 文件

PHP < 8.1
函式 計數並迭代(迭代器 $value) {
if (!(
$value instanceof 可計數)) {
throw new
類型錯誤('值必須是可計數的');
}

foreach (
$value as $val) {
echo
$val;
}

計數($value);
}
PHP 8.1
函式 計數並迭代(迭代器&可計數 $value) {
foreach (
$value as $val) {
echo
$val;
}

計數($value);
}

當一個值需要同時滿足多個類型約束時,請使用交集類型。

目前無法將交集類型和聯集類型混合在一起,例如 A&B|C

永不返回類型 RFC 文件

PHP < 8.1
函式 redirect(字串 $uri) {
header('Location: ' . $uri);
exit();
}

函式
redirectToLoginPage() {
redirect('/login');
echo
'Hello'; // <- 無效程式碼
}
PHP 8.1
函式 redirect(字串 $uri): never {
header('Location: ' . $uri);
exit();
}

函式
redirectToLoginPage(): never {
redirect('/login');
echo
'Hello'; // <- 靜態分析偵測到的無效程式碼
}

never 類型宣告的函式或方法表示它不會回傳值,並且會丟出例外或透過呼叫 die()exit()trigger_error() 或類似函式來結束腳本的執行。

Final 類別常數 RFC 文件

PHP < 8.1
類別 Foo
{
公開 常數
XX = "foo";
}

類別
Bar 繼承 Foo
{
公開 常數
XX = "bar"; // 沒有錯誤
}
PHP 8.1
類別 Foo
{
final 公開 常數
XX = "foo";
}

類別
Bar 繼承 Foo
{
公開 常數
XX = "bar"; // 致命錯誤
}

現在可以宣告 final 類別常數,使其無法在子類別中被覆寫。

明確的八進位數字表示法 RFC 文件

PHP < 8.1
016 === 16; // false,因為 `016` 是八進位的 `14`,容易造成混淆
016 === 14; // true
PHP 8.1
0o16 === 16; // false — 使用明確的表示法就不會混淆
0o16 === 14; // true

現在可以使用明確的 0o 前綴來撰寫八進位數字。

纖程 Fibers RFC 文件

PHP < 8.1
$httpClient->request('https://example.com/')
->
then(function (Response $response) {
return
$response->getBody()->buffer();
})
->
then(function (string $responseBody) {
print
json_decode($responseBody)['code'];
});
PHP 8.1
翻譯:
$response = $httpClient->request('https://example.com/'); 發送請求到 'https://example.com/' 並將回應儲存到 $response 變數
print json_decode($response->getBody()->buffer())['code']; 取得回應內容、緩衝、解碼 JSON 並輸出 'code' 鍵的值

翻譯:Fiber 是一種用於實現輕量級協作式並行處理的原始類型。它們是一種建立程式碼區塊的方式,這些區塊可以像 Generator 一樣暫停和恢復,但是可以從堆疊中的任何位置進行。Fiber 本身並不會神奇地提供並行處理能力,仍然需要一個事件迴圈。然而,它們允許阻塞和非阻塞實現共享相同的 API。

翻譯:Fiber 可以擺脫先前使用 `Promise::then()` 或基於 Generator 的協程所看到的樣板程式碼。函式庫通常會圍繞 Fiber 建構進一步的抽象層,因此不需要直接與它們互動。

翻譯:支援對字串鍵陣列進行陣列解包 RFC 文件

PHP < 8.1
翻譯:
$arrayA = ['a' => 1]; 定義 $arrayA 陣列
$arrayB = ['b' => 2]; 定義 $arrayB 陣列
$result = array_merge(['a' => 0], $arrayA, $arrayB); 使用 array_merge 合併陣列,後面的值會覆蓋前面的值
// ['a' => 1, 'b' => 2] 結果
PHP 8.1
翻譯:
$arrayA = ['a' => 1]; 定義 $arrayA 陣列
$arrayB = ['b' => 2]; 定義 $arrayB 陣列
$result = ['a' => 0, ...$arrayA, ...$arrayB]; 使用展開運算符 ... 合併陣列,後面的值會覆蓋前面的值
// ['a' => 1, 'b' => 2] 結果

翻譯:PHP 之前透過展開運算符支援在陣列內解包,但僅限於陣列具有整數鍵的情況。現在也可以解包具有字串鍵的陣列。

翻譯:效能提升

翻譯:Symfony 範例應用程式請求時間
翻譯:連續執行 25 次,每次 250 個請求(秒)
翻譯:(數值越小越好)

翻譯:結果(相對於 PHP 8.0)

  • 翻譯:Symfony 範例應用程式速度提升 23.0%
  • 翻譯:WordPress 速度提升 3.5%

翻譯:PHP 8.1 中與效能相關的功能

  • 翻譯:ARM64 (AArch64) 的 JIT 後端
  • 翻譯:繼承快取(避免在每個請求中重新連結類別)
  • 翻譯:快速類別名稱解析(避免小寫和雜湊查詢)
  • 翻譯:timelib 和 ext/date 效能提升
  • 翻譯:SPL 檔案系統迭代器提升
  • 翻譯:serialize/unserialize 優化
  • 翻譯:一些內部函數的優化 (get_declared_classes(), explode(), strtr(), strnatcmp(), dechex())
  • 翻譯:JIT 的改進和修正

翻譯:新的類別、介面和函數

  • 翻譯:新的 `#[ReturnTypeWillChange]` 屬性。
  • 新增 fsyncfdatasync 函式。
  • 新增 array_is_list 函式。
  • 新增 Sodium XChaCha20 函式。

棄用項目及向下相容性破壞

  • 將 null 傳遞給不可為 null 的內部函式參數已被棄用。
  • PHP 內建類別方法中的暫定回傳型別
  • Serializable 介面已被棄用。
  • HTML 實體編碼/解碼函式預設會處理單引號並進行替換。
  • $GLOBALS 變數限制。
  • MySQLi:預設錯誤模式設定為例外。
  • 隱式不相容的 float 到 int 轉換已被棄用。
  • finfo 擴充:file_info 資源已遷移到現有的 finfo 物件。
  • IMAP:imap 資源已遷移到 IMAP\Connection 類別物件。
  • FTP 擴充:連線資源已遷移到 FTP\Connection 類別物件。
  • GD 擴充:字型識別碼已遷移到 GdFont 類別物件。
  • LDAP:資源已遷移到 LDAP\ConnectionLDAP\ResultLDAP\ResultEntry 物件。
  • PostgreSQL:資源已遷移到 PgSql\ConnectionPgSql\ResultPgSql\Lob 物件。
  • Pspell:pspell、pspell config 資源已遷移到 PSpell\DictionaryPSpell\Config 類別物件。
To Top