類別在其方法上有契約
<?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 會拋出例外。
因此,列舉類型是最終類型,不能被繼承。