## 为什么枚举不可扩展

类在方法有契约：

    <?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

    // 当枚举不是 final 时考虑做的实验代码。
    // 注意在 PHP 中实际不起作用。
    enum MoreErrorCode extends ErrorCode {
        case PEBKAC;
    }

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

    fot(MoreErrorCode::PEBKAC);

    ?>

根据正常的继承规则，继承另一个类的类将通过类型检查。

问题在于 `quux()` 中的 match 语句不再涵盖所有情况。因为它不知道 `MoreErrorCode::PEBKAC`，所以匹配语句会抛出异常。

因此，枚举是 final，不能扩展。

`↑` and `↓` to navigate • `Enter` to select • `Esc` to close • `/` to open