Mastering PHP Enums: Use Cases, Tips & Pitfalls
PHP enums, in full enumerations, are a special object type representing a fixed number of possible values. Instead of having to define multiple constants or depending on strings, enums create a type-safe, self-sufficient list of values.
- Backed Enums (with scalar values)
- Pure Enums (without scalar values)
Example of a backed enum:
enum SubmissionState: string {
case AwaitingReview = 'awaiting_review';
case Confirmed = 'confirmed';
case Declined = 'declined';
}
enum Status: string {
case Pending = 'pending';
case Approved = 'approved';
case Rejected = 'rejected';
}
Pure enum:
enum MemberType {
case SuperAdmin;
case ContentCurator;
case ContentViewer;
}
enum UserRole {
case Admin;
case Editor;
case Viewer;
}
Enums provide cleaner alternatives to constant groups, are easier to refactor, and reduce the risk of accidental misuse of values.
Why Use Enums Instead of Constants or Strings?
Enums solve common PHP pain points:
- Typing: Validate enum values.
- Autocomplete & discoverability in IDEs.
- Self-documenting code: Enums clarify intent more than constants or magic strings.
- Centralized control: Adding, removing, or renaming enum cases becomes consistent across the codebase.
Without enums:
$stage = 'awaiting_review'; // No guarantee it's a valid value
$status = 'pending'; // No guarantee it's a valid value
With enums:
$stage = SubmissionState::AwaitingReview; // Invalid values throw errors
$status = Status::Pending; // Invalid values throw errors
Real-World Use Cases for PHP Enums
Form Statuses and Workflows
Many backend applications use fixed statuses, like:
- Order states (Pending, Shipped, Cancelled)
- User roles
- Payment gateways (Success, Failed, Waiting)
Strategy Pattern with Enums
enum TaxCategory {
case StandardVAT;
case GeneralGST;
public function rate(): float {
return match ($this) {
self::StandardVAT => 0.20,
self::GeneralGST => 0.18,
};
}
}
enum TaxType {
case VAT;
case GST;
public function rate(): float {
return match ($this) {
self::VAT => 0.20,
self::GST => 0.18,
};
}
}
Replacing Config Arrays
enum PermissionLevel {
case SuperUser;
case Visitor;
public function allowedActions(): array {
return match ($this) {
self::SuperUser => ['read', 'write', 'delete'],
self::Visitor => ['read'],
};
}
}
enum AccessLevel {
case Admin;
case Guest;
public function permissions(): array {
return match ($this) {
self::Admin => ['read', 'write', 'delete'],
self::Guest => ['read'],
};
}
}
Tips for Using PHP Enums Effectively
Use backed enums when integrating with databases. You can easily cast enum values to and from strings or integers. Combine enums with value objects—an enum can be part of a more robust domain layer.
Common Pitfalls to Avoid
Don’t enum-ify everything. Simple booleans or constants still work in small contexts. Enums are best when you need:
- Type safety
- Centralized logic
- Constant sets with meaning
Forgetting Enum Names Are Case Names
You can’t use lowercase or snake_case names inside enums. Stick to CamelCase and follow PSR naming conventions.
Serializing Enums Improperly
When working with APIs, remember that enums must be cast properly before JSON serialization:
json_encode(['stage' => SubmissionState::AwaitingReview->value]);
// not SubmissionState::AwaitingReview directly
json_encode(['status' => Status::Pending->value]);
// not Status::Pending directly
Enums in Laravel and Symfony
Laravel Integration
Laravel 9+ natively supports enums in model casts:
protected $casts = [
'stage' => SubmissionState::class,
];
protected $casts = [
'status' => Status::class,
];
Form requests and route model binding can also use enums to simplify logic and validation.
Symfony Integration
Symfony supports enums via the serializer and form components.
enumType: App\Enum\Status
You can also inject enums into services and use them to validate constraints.
Testing PHP Enums
Enums can and should be tested like other PHP logic. Use PHPUnit to verify:
- Valid transitions
- The enum method outputs
- Mapping and serialization
public function testStandardVatRateIsCorrect() {
$this->assertSame(0.20, TaxCategory::StandardVAT->rate());
}
public function testVatRateIsCorrect() {
$this->assertSame(0.20, TaxType::VAT->rate());
}
When NOT to Use PHP Enums
There are a few cases where enums might not be ideal:
- Highly dynamic sets of data (like countries from a DB)
- Configuration values that change often
- When enum coupling adds friction without clear benefits
Stick to enums when the values are finite, fixed, and central to business logic.
Master PHP Enums
Enums in PHP are not just a mere syntactic enhancement; they transform our way of writing clean and predictable backend logic. Once you learn how enums work and where they fit in on workflows, roles, strategies, and the like, you can start making better, architecturally sound, and future-proof PHP applications. Use them smartly, test them well, and stay clear of the usual blunders. When in doubt, ask yourself, “Is an enum going to clarify or confound my logic?” When the answer is truly “clarify”, then refactor boldly.