열거형(Enum)이 상속될 수 없는 이유
열거형(Enum)이 상속될 수 없는 이유
이 페이지는 왜 PHP의 열거형이 final이며 상속이 불가능한지를 설명해 드려요. 클래스의 계약(contract)이 메서드에 있는 반면, 열거형의 계약은 케이스에 있기 때문에 생기는 타입 안전성 문제가 핵심이에요.
본문
클래스는 메서드에 계약이 있어요:
<?php
class A {}
class B extends A {}
function foo(A $a) {}
function bar(B $b)
{
foo($b);
}
이 코드는 B 가 A 의 계약을 따르기 때문에 타입 안전해요. 그리고 공변/반변(co/contra-variance)의 마법 덕분에 메서드에 대한 기대는 예외를 제외하고는 모두 유지돼요.
열거형은 메서드가 아니라 케이스에 계약이 있어요:
<?php
enum ErrorCode
{
case SOMETHING_BROKE;
}
function quux(ErrorCode $errorCode)
{
// When written, this code appears to cover all cases
match ($errorCode) {
ErrorCode::SOMETHING_BROKE => true,
};
}
함수 quux 안의 match 문은 ErrorCode 의 모든 케이스를 커버한다고 정적으로 분석할 수 있어요.
하지만 열거형을 확장할 수 있다고 상상해 보세요:
<?php
// Thought experiment code where enums are not final.
// Note, this won't actually work in PHP.
enum MoreErrorCode extends ErrorCode
{
case PEBKAC;
}
function fot(MoreErrorCode $errorCode)
{
quux($errorCode);
}
fot(MoreErrorCode::PEBKAC);
일반적인 상속 규칙에서는 다른 클래스를 상속한 클래스는 타입 검사를 통과하게 돼요.
문제는 quux() 의 match 문이 더 이상 모든 케이스를 커버하지 않게 된다는 거예요. MoreErrorCode::PEBKAC 를 모르기 때문에 match 가 예외를 던질 거예요.
이런 이유로 열거형은 final 이며 상속될 수 없어요.
더 알아보기
열거형의 케이스 계약이나 match 표현식에 대해 더 알아보고 싶다면 PHP 매뉴얼의 열거형 문서를 함께 확인해 보세요.