How to Define and Use Enums in PHP 8.1

In this article, you will learn how to define and use Enumerations (Enums) in PHP 8.1. We will cover the differences between Pure Enums and Backed Enums, explore how to instantiate and compare them, and demonstrate how to add methods to Enums to make your codebase more type-safe and readable.

What are Enums?

Introduced in PHP 8.1, Enums (Enumerations) are a new data type that allows you to define a custom type limited to a discrete set of possible values. They are highly beneficial for representing constant values like order statuses, user roles, or days of the week, ensuring type safety throughout your application.

1. Pure Enums

A Pure Enum is an enum where the cases do not have any associated scalar value (such as a string or integer). They are represented only by their case name.

Defining a Pure Enum

enum Status 
{
    case Pending;
    case Active;
    case Suspended;
}

Using a Pure Enum

You can reference enum cases directly and use them as type hints in functions or class properties.

function transitionTo(Status $status): void 
{
    echo "Transitioning to status: " . $status->name;
}

// Usage
transitionTo(Status::Active);

To get the name of a case, use the read-only name property:

echo Status::Pending->name; // Outputs: Pending

2. Backed Enums

Often, you need to store enum values in a database or send them over an API. In these cases, you use Backed Enums, which associate a scalar value (either string or int) with each case.

Defining a Backed Enum

To define a Backed Enum, declare the scalar type (either string or int) next to the enum name, and assign values to each case.

enum UserRole: string 
{
    case Admin = 'administrator';
    case Editor = 'editor';
    case Guest = 'guest';
}

Accessing Values

Backed Enums have a read-only value property in addition to the name property.

echo UserRole::Admin->value; // Outputs: administrator
echo UserRole::Admin->name;  // Outputs: Admin

Instantiating from a Scalar Value

You can instantiate a Backed Enum from a database value using the from() or tryFrom() methods:

// Using from()
$role = UserRole::from('editor'); // Returns UserRole::Editor

// Using tryFrom()
$invalidRole = UserRole::tryFrom('superuser'); // Returns null

3. Enum Methods

Enums can also contain methods. This allows you to bundle logic directly with the enumeration cases, reducing the need for external helper classes.

enum SubscriptionType: string 
{
    case Free = 'free';
    case Premium = 'premium';

    public function getPrice(): float 
    {
        return match($this) {
            self::Free => 0.00,
            self::Premium => 19.99,
        };
    }
}

// Usage
$mySubscription = SubscriptionType::Premium;
echo $mySubscription->getPrice(); // Outputs: 19.99

4. Comparing Enums

Because enum cases are singletons, you can compare them directly using the strict comparison operator (===).

$status = Status::Active;

if ($status === Status::Active) {
    echo "The status is indeed active.";
}