PHP Conference Japan 2024

為何列舉無法被繼承

類別在其方法上有契約

<?php

class A {}
class
B extends A {}

function
foo(A $a) {}

function
bar(B $b) {
foo($b);
}
?>

這段程式碼是類型安全的,因為 B 遵循 A 的契約,並且透過共變/逆變的機制,任何對方法的預期都將被保留,例外情況除外。

列舉在其成員上具有契約,而非方法

<?php

enum ErrorCode {
case
SOMETHING_BROKE;
}

function
quux(ErrorCode $errorCode)
{
// 撰寫時,這段程式碼看似涵蓋了所有情況
match ($errorCode) {
ErrorCode::SOMETHING_BROKE => true,
}
}

?>

函式 quux 中的 match 陳述式可以透過靜態分析來確認涵蓋了 ErrorCode 中的所有情況。

但想像一下,如果允許擴展列舉類型的話…

<?php

// 思想實驗程式碼,其中列舉類型並非最終類型。
// 注意,這在 PHP 中實際上無法運作。
enum MoreErrorCode extends ErrorCode {
case
PEBKAC;
}

function
fot(MoreErrorCode $errorCode) {
quux($errorCode);
}

fot(MoreErrorCode::PEBKAC);

?>

在一般的繼承規則下,繼承另一個類別的類別會通過類型檢查。

問題在於 quux() 中的 match 陳述式不再涵蓋所有情況。因為它不知道 MoreErrorCode::PEBKAC,match 會拋出例外。

因此,列舉類型是最終類型,不能被繼承。

新增註記

使用者貢獻的註記

此頁面沒有使用者貢獻的註記。
To Top