an image related to programming containing css php js html texts

Cleaner Logic: Using PHP Enums and Match Expressions

Beyond Magic Strings

In the past, representing a user's role or an order's status in PHP meant using integers or strings. This approach is error-prone because there is no built-in way to enforce that a variable contains a valid value. If a developer typos 'pedning' instead of 'pending', the system fails silently. PHP 8.1 introduced Enums, and combined with the match expression, they provide a robust way to handle state-heavy logic with full type safety.

Defining a Backed Enum

A Backed Enum allows you to associate a scalar value (string or int) with an internal case. This is perfect for when you need to store the value in a database but want to use objects in your code. Using string backing ensures that your database remains readable while your PHP code stays type-safe.

enum OrderStatus: string {
    case PENDING = 'pending';
    case SHIPPED = 'shipped';
    case DELIVERED = 'delivered';
    case CANCELLED = 'cancelled';
}

Implementing Business Logic with Match

The match expression is the modern successor to the switch statement. Unlike switch, match is an expression, meaning it returns a value. It also requires exhaustive cases and uses strict comparison (===). This prevents the subtle bugs often found in switch statements when comparing integers to strings. In the example below, we map the Enum cases to user-friendly labels.

public function getStatusLabel(OrderStatus $status): string {
    return match($status) {
        OrderStatus::PENDING => 'Your order is being prepared.',
        OrderStatus::SHIPPED => 'The package is on its way!',
        OrderStatus::DELIVERED => 'Package has arrived.',
        OrderStatus::CANCELLED => 'This order was voided.',
    };
}

Adding Methods to Enums

One of the most powerful features of PHP Enums is that they can contain methods. This allows you to encapsulate logic directly within the Enum case itself, adhering to the principles of Object-Oriented Programming. For instance, you can check if a status allows for a specific action like cancellation.

enum OrderStatus: string {
    case PENDING = 'pending';
    case SHIPPED = 'shipped';
    case DELIVERED = 'delivered';
    case CANCELLED = 'cancelled';

    public function canBeCancelled(): bool {
        return match($this) {
            self::PENDING => true,
            default => false,
        };
    }
}

Why This Matters for Maintainability

Using these features makes your code self-documenting. If you add a new case to the OrderStatus enum, the match expression will throw an UnhandledMatchError if you forget to update the corresponding logic elsewhere. This 'fail-fast' behavior ensures your application doesn't enter an inconsistent state during runtime. By adopting Enums and Match, you eliminate the need for manual validation and provide your IDE with better type-hinting capabilities. It turns potential runtime errors into predictable, catchable logic flows, making your codebase much easier to refactor and scale as your application grows.