Skip to content
Enums and Match Expressions
step 1/7

Reading — step 1 of 7

Learn

~3 min readModern PHP 8+

PHP 8.1 added native enums — finite, type-safe sets of values. Combined with match expressions (PHP 8.0), they replace many of PHP's old patterns for finite-state code.

Note: Judge0's PHP version may be older — these features need PHP 8.0+ for match and 8.1+ for enums.

Enum basics

<?php
enum Status {
    case Active;
    case Archived;
    case Pending;
}

$s = Status::Active;

if ($s === Status::Active) {
    echo "active";
}

Cases are CONSTANTS — exactly equal under ===. Always type-safe.

Backed enums — with values

For enums that need a stored value (database, API, etc.):

enum Status: string {
    case Active = 'active';
    case Archived = 'archived';
    case Pending = 'pending';
}

$s = Status::Active;
echo $s->value;                      // 'active'

// Parse from value:
$s = Status::from('active');         // Status::Active
$s = Status::from('unknown');        // ValueError thrown
$s = Status::tryFrom('unknown');     // null returned (failable)

String-backed and int-backed are the two options. The value property exposes the underlying value. from() parses (throws on invalid). tryFrom() returns null on invalid.

Methods on enums

enum Status: string {
    case Active = 'active';
    case Archived = 'archived';
    case Pending = 'pending';
    
    public function label(): string {
        return match($this) {
            Status::Active => 'Active',
            Status::Archived => 'Archived',
            Status::Pending => 'Pending — Review Required',
        };
    }
    
    public function isFinal(): bool {
        return $this === Status::Archived;
    }
}

echo Status::Pending->label();    // 'Pending — Review Required'

Enums can have methods, constants, implement interfaces. Cannot have constructors or properties (apart from the implicit name and optionally value).

Listing all cases

foreach (Status::cases() as $case) {
    echo $case->name . ": " . $case->value . "\n";
}

cases() returns all enum values. Useful for dropdowns, validation, etc.

match expressions

The match expression (PHP 8.0+) is like switch but as an EXPRESSION (returns a value), with strict comparison and exhaustive checks:

$status = 'active';

$label = match($status) {
    'active' => 'Active',
    'archived', 'deleted' => 'Inactive',     // multiple values per arm
    default => 'Unknown',
};

Differences from switch:

  • Returns a value (use as expression)
  • Strict equality (===) — no '1' == 1 surprises
  • No fall-through; no break needed
  • Throws UnhandledMatchError if nothing matches and no default

match with conditions

$n = 42;

$category = match(true) {
    $n < 0 => 'negative',
    $n === 0 => 'zero',
    $n < 10 => 'small',
    $n < 100 => 'medium',
    default => 'large',
};

The match(true) pattern lets you express ranges and complex conditions. Each arm is evaluated as a boolean.

Combining enums and match

This is the killer pattern:

enum Direction { case North; case South; case East; case West; }

function opposite(Direction $d): Direction {
    return match($d) {
        Direction::North => Direction::South,
        Direction::South => Direction::North,
        Direction::East => Direction::West,
        Direction::West => Direction::East,
    };
}

Compiler verifies exhaustiveness in PHP 8.1+ for backed enums. Add a new case → existing matches still need updating to compile.

Common mistakes

  • Adding properties to an enum — not allowed. Use methods that compute from this>nameorthis->name or this->value.
  • Using switch when match would be better — match has strict equality and is exhaustive. Modern PHP code uses match.
  • Forgetting tryFrom for fallible parsing — from() throws; tryFrom() returns null. Pick based on whether the input is trusted.
  • Mixing enums with strings/ints elsewhere — backed enums make this safer with from()/value, but you can still slip up.

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…