类对其方法有契约
<?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
,所以匹配将抛出异常。
因此,枚举是最终的,不能扩展。