Klassen haben Vereinbarungen bezüglich ihrer Methoden:
<?php
class A {}
class B extends A {}
function foo(A $a) {}
function bar(B $b) {
foo($b);
}
?>
Dieser Code ist typsicher, da B der Vereinbarung von A folgt, und die Magie der Ko-/Kontra-Varianz sicherstellt, dass bis auf Exceptions alle an die Methoden gestellten Erwartungen erfüllt werden.
Enums haben Vereinbarungen über ihre Fälle, nicht über ihre Methoden:
<?php
enum ErrorCode {
case SOMETHING_BROKE;
}
function quux(ErrorCode $errorCode)
{
// Mit diesem Code werden offenbar alle Fälle abgedeckt
match ($errorCode) {
ErrorCode::SOMETHING_BROKE => true,
}
}
?>
Die Anweisung match in der Funktion quux
kann statisch
analysiert werden, um alle Fälle in ErrorCode abzudecken.
Aber angenommen, es wäre erlaubt, Enums zu erweitern:
<?php
// Ein gedankliches Code-Experiment, bei dem Enums nicht final sind.
// Es ist zu beachten, dass dies in PHP nicht funktioniert.
enum MoreErrorCode extends ErrorCode {
case PEBKAC;
}
function fot(MoreErrorCode $errorCode) {
quux($errorCode);
}
fot(MoreErrorCode::PEBKAC);
?>
Nach den normalen Vererbungsregeln besteht eine Klasse, die eine andere Klasse erweitert, die Typprüfung.
Das Problem besteht darin, dass die Anweisung match in
quux()
nicht mehr alle Fälle abdeckt. Da sie
MoreErrorCode::PEBKAC
nicht kennt, löst der Abgleich eine
Exception aus.
Aus diesem Grund sind Enums final und können nicht erweitert werden.