PHP 8.4.1 Released!

Почему перечисления нерасширяемы

В классах обязательства по контрактам берут на себя методы:

<?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,
};
}

?>

Статический анализ выражения match в функции quux показывает, что проверяется каждый вариант перечисления ErrorCode.

Но представьте, что перечисления разрешили бы расширять:

<?php

// Код мысленного эксперимента, в котором перечисления не окончательны.
// Обратите внимание, что это не будет работать в PHP
enum MoreErrorCode extends ErrorCode
{
case
PEBKAC;
}

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

fot(MoreErrorCode::PEBKAC);

?>

По стандартным правилам наследования класс-наследник пройдёт проверку типа.

Проблема состояла бы в том, что выражение match в функции quux() уже не покрывало бы каждый вариант перечисления. И поскольку выражение проверки не знает о варианте MoreErrorCode::PEBKAC, сопоставление выбросит исключение.

Поэтому перечисления окончательны и их нельзя расширять.

Добавить

Примечания пользователей

Пользователи ещё не добавляли примечания для страницы
To Top