열거형 (Enum)
과거 PHP에서는 특정 상태(예: 주문 상태, 사용자 역할 등)를 구분하기 위해 클래스 내부에 상수(const STATUS_PENDING = 1;)를 정의해 사용하곤 했습니다. 하지만 이러한 상수 방식은 타입 안정성이 떨어지고(엉뚱한 정수를 대입해도 막을 수 없음), 단순한 스칼라 값에 불과하여 의미를 부여하기 까다로웠습니다.
PHP 8.1부터는 이러한 단점을 극복하고 강력한 타입 안정성과 객체지향적인 설계를 제공하는 열거형(Enum)이 공식 도입되었습니다.
그림: PHP 8.1+ Pure Enum(단순 식별형)과 Backed Enum(상수 값 매핑형)의 구조 차이
1. 단순 열거형 (Pure Enum)
단순 열거형은 추가적인 스칼라 값을 가지지 않고, 오직 각 분기(Case)의 존재 자체가 하나의 유일한 상태 값으로 취급되는 형태입니다.
<?php
declare(strict_types=1);
// 1. 단순 열거형 선언
enum Status
{
case Draft;
case Published;
case Archived;
}
// 2. 변수 타입 제한 및 객체 대입
function publishPost(Status $status): void
{
if ($status === Status::Published) {
echo "게시물이 전 세계에 공개됩니다.<br>";
}
}
// 올바른 호출 (타입 안정성 보장)
publishPost(Status::Published);
// 잘못된 호출 (컴파일/런타임 에러 자동 발생)
// publishPost("Published"); // ❌ TypeError 발생! (문자열은 Status 타입이 아님)
?>
2. 백드 열거형 (Backed Enum)
데이터베이스에 저장하거나 API 응답으로 내보낼 때, 각 케이스를 정수(int)나 문자열(string) 형태의 스칼라 값으로 매핑(Backing)해야 할 때가 많습니다. 이를 백드 열거형(Backed Enum)이라고 부릅니다.
백드 열거형은 정의할 때 상속처럼 콜론(:) 뒤에 string 또는 int 타입을 선언해 주어야 합니다.
<?php
declare(strict_types=1);
// string 타입의 백드 열거형 정의
enum UserRole: string
{
case Admin = 'administrator';
case Editor = 'editor';
case Guest = 'guest';
}
// 1. 읽기 전용 프로퍼티 자동 지원
$myRole = UserRole::Admin;
echo "케이스 이름: " . $myRole->name . "<br>"; // 출력: Admin
echo "케이스 실제값: " . $myRole->value . "<br>"; // 출력: administrator
// 2. 값(Value)을 통해 Enum 객체로 역복원 (Deserialization)
$dbValue = 'editor';
// form() 메서드는 값과 일치하는 Enum 객체를 리턴합니다. 일치하는 값이 없으면 ValueError 에러를 냅니다.
$roleObj = UserRole::from($dbValue);
echo "복원된 역할: " . $roleObj->name . "<br>"; // 출력: Editor
// tryFrom() 메서드는 일치하지 않을 때 Exception 대신 null을 리턴하므로 훨씬 안전합니다.
$badRole = UserRole::tryFrom('hacker');
if ($badRole === null) {
echo "올바르지 않은 권한명입니다.<br>";
}
?>
3. 열거형 메서드 (Enum Methods)
PHP의 Enum은 내부적으로 특수한 클래스로 구현되어 있기 때문에, 일반 클래스처럼 내부에 메서드를 정의하여 특정 케이스에 따른 비즈니스 논리를 은닉하여 캡슐화할 수 있습니다.
<?php
declare(strict_types=1);
enum OrderStatus: string
{
case Pending = 'pending';
case Shipping = 'shipping';
case Delivered = 'delivered';
// 클래스처럼 메서드 정의 가능
public function getKoreanLabel(): string
{
// match 표현식과 결합하여 환상적인 가독성을 냅니다.
return match($this) {
self::Pending => '대기 중',
self::Shipping => '배송 중',
self::Delivered => '배송 완료',
};
}
// 인터페이스 구현도 가능합니다.
}
$status = OrderStatus::Shipping;
echo "현재 상태 한글명: " . $status->getKoreanLabel() . "<br>"; // 출력: 배송 중
?>
4. 열거형 모든 케이스 조회
Enum에 정의된 모든 케이스의 목록을 가져오고 싶다면 static 메서드인 cases()를 호출합니다.
<?php
$allRoles = UserRole::cases();
foreach ($allRoles as $role) {
echo "역할: " . $role->name . " (값: " . $role->value . ")<br>";
}
?>
📂 열거형 요약 및 특징
- 클래스 상속 불가: Enum은 이미 내부적으로 특수한 클래스를 구현하고 있으므로, 다른 Enum이나 일반 클래스로부터 상속을 받거나(
extends), 다른 클래스의 부모가 될 수 없습니다. (단, 인터페이스 구현(implements)은 허용됩니다.) - 인스턴스 생성 불가:
new UserRole()과 같이 직접 인스턴스화하는 행위는 문법적으로 완벽히 차단됩니다.
이전 학습
« 디자인 패턴 개요
서브목차