php-enums-en-php

Enums in PHP

  • 3 min

A enum is a type composed of a closed set of valid cases.

Imagine you’re programming the status of a blog post. You have three options: Draft, Published, and Archived.

The old way (Chaos):

class Post {
    public const STATUS_DRAFT = 'draft';
    public const STATUS_PUBLISHED = 'published';
    
    public string $status; // Can be any string
}

$post->status = 'pubished'; // ❌ Typo that PHP swallows without complaint
Copied!

The modern way (Enums): An Enum is a special object type that only allows a limited, predefined set of values. It’s a closed list.

Basic Enums (Pure Enums)

We define an Enum using the enum keyword.

enum PostStatus {
    case DRAFT;
    case PUBLISHED;
    case ARCHIVED;
}
Copied!

Now we can use PostStatus as a Data Type in our functions.

class Post {
    // Total safety! We only accept valid values
    public PostStatus $status;
}

$post = new Post();
$post->status = PostStatus::PUBLISHED; // ✅ Correct

// $post->status = 'published'; 
// ❌ FATAL ERROR: Must be of type PostStatus, string given
Copied!

No more manually validating if the string is correct. PHP does it for you.

Backed Enums

Sometimes you need to save that Enum to a database. The database doesn’t understand PHP objects; it understands strings ('draft') or numbers (1).

For that, we use Backed Enums. We assign a scalar value (int or string) to each case.

// We declare this Enum is "backed" by strings
enum PostStatus: string {
    case DRAFT = 'draft';
    case PUBLISHED = 'published';
    case ARCHIVED = 'archived';
}
Copied!

Automatic Conversion

  • From Enum to value: Use the ->value property.
echo PostStatus::DRAFT->value; // 'draft'
Copied!
  • From value to Enum: Use the ::from() or ::tryFrom() method.
$status = PostStatus::from('published'); // Returns the PostStatus::PUBLISHED object
Copied!

Use tryFrom() when the value comes from an untrusted input.

If it doesn’t exist, tryFrom() returns null; from() throws a ValueError, useful when an invalid value represents a failure you don’t want to hide.

Enums with Methods

PHP enums can have methods, allowing you to keep some of their behavior together with the type.

They are classes after all. They can have internal logic. This is great for encapsulating presentation logic.

enum PostStatus: string {
    case DRAFT = 'draft';
    case PUBLISHED = 'published';
    case ARCHIVED = 'archived';

    // Method to get a color for the frontend
    public function color(): string {
        return match($this) {
            self::DRAFT => 'gray',
            self::PUBLISHED => 'green',
            self::ARCHIVED => 'red',
        };
    }
    
    // Method to get a readable label
    public function label(): string {
        return match($this) {
            self::DRAFT => 'In Editing',
            self::PUBLISHED => 'Visible',
            self::ARCHIVED => 'Hidden',
        };
    }
}
Copied!

Look at how clean your code is in the view:

$status = PostStatus::PUBLISHED;

echo "<span class='badge-{$status->color()}'>{$status->label()}</span>";
// Output: <span class='badge-green'>Visible</span>
Copied!

No more giant if/else blocks in your HTML templates. The Enum knows how to render itself.

Listing All Cases (cases)

If you need to populate a <select> with all possible options, enums provide the static method ::cases().

foreach (PostStatus::cases() as $option) {
    echo "<option value='{$option->value}'>{$option->label()}</option>";
}
Copied!