Classes possuem contratos em seus métodos:
<?php
class A {}
class B extends A {}
function foo(A $a) {}
function bar(B $b) {
foo($b);
}
?>
Esse código é correto para tipos, pois B segue o contrato de A, e através da co e contra variância, quaisquer expectativas a respeito dos métodos será atendida.
Enums possuem contratos em seus itens, não em seus métodos:
<?php
enum ErrorCode {
case SOMETHING_BROKE;
}
function quux(ErrorCode $errorCode)
{
// Nesse primeiro momento, esse código prevê todos os casos
match ($errorCode) {
ErrorCode::SOMETHING_BROKE => true,
}
}
?>
A instrução match na função quux
pode ser analisada estaticamente
para verificar se cobre todos os casos possíveis em ErrorCode.
Mas imagine que seja possível estender enums, assim:
<?php
// Apenas para o exemplo onde enums não são finais.
// Isto *não* funciona no PHP.
enum MoreErrorCode extends ErrorCode {
case PEBKAC;
}
function fot(MoreErrorCode $errorCode) {
quux($errorCode);
}
fot(MoreErrorCode::PEBKAC);
?>
Em condições normais de herança, uma classe que estende outro passará na checagem de tipos.
O problema ocorreria na instrução match da função quux()
que agora não cobre todos
os casos. Porque a função não prevê o item MoreErrorCode::PEBKAC
o match irá falhar com uma exceção.
Por conta disso, enums são finais e não podem ser estendidos.