Blog

New in PHP 8.1: Enums - A Concrete Example

With PHP 8.1, enumerations, known as enums, have finally made their way into the language. Here's an example of how enum can be used in practice.

Before PHP 8.1, one had to rely on class constants for similar behavior:

class Status
{
    public const IDLE = 1;
    public const RUNNING = 2;
    public const ERROR = 3;
}

Why would you do this? The following example illustrates the reasoning. Let's say we have a task. What statuses exist besides idle? Is idle even a valid status?

Task::create([
    'title' => 'My special task',
    'status' => 'idle'
]);

Here, the aforementioned class could be helpful:

Task::create([
    'title' => 'My special task',
    'status' => Status::IDLE
]);

Switching to enum

Now, let's switch to enum. The Status class becomes:

enum Status: int
{
    case IDLE = 1;
    case RUNNING = 2;
    case ERROR = 3;
}

And we can create our task as follows:

Task::create([
    'title' => 'My special task',
    'status' => Status::IDLE->value
]);

In the database, the status will now be stored as the value of IDLE, which is 1. But how do we get IDLE back if we only have the value 1? Here's an example:

$task = Task::find(23);

$status = Status::from($task->status);

This way, we obtain an Enum object. What is the advantage here?

Additional Methods

Enums can have methods, allowing us to implement a method that returns the readable status, for example:

enum Status: int
{
    case IDLE = 1;
    case RUNNING = 2;
    case ERROR = 3;

    public function readable(): string
    {
        return match ($this) {
            self::IDLE => 'is idle',
            self::RUNNING => 'is running',
            self::ERROR => 'an error occurred',
        };
    }
}

Now, we can add to the previous call:

$status = Status::from($task->status)->readable();

...and in this case, we would get is idle as the result.

Possible Values

To output all valid statuses, you can use the following code (this example uses Laravel Blade):

<select name="status">
    @foreach(Status::cases() as $status)
        <option value="{{ $status->value }}">
            {{ $status->readable() }}
        </option>
    @endforeach
</select>