Menu
Coddy logo textTech

Enums (PHP 8.1)

Part of the Object Oriented Programming section of Coddy's PHP journey — lesson 59 of 91.

Before PHP 8.1, representing a fixed set of values like statuses or types meant using class constants or magic strings - both error-prone approaches. Enums (enumerations) provide a proper way to define a type that can only hold specific, predefined values.

Define an enum using the enum keyword:

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

$status = Status::Active;
echo $status->name;

Output:

Active

Enums can also have backed values - string or integer values associated with each case. This is useful when storing enums in databases or APIs:

<?php
enum Status: string {
    case Pending = 'pending';
    case Active = 'active';
    case Completed = 'completed';
}

$status = Status::Active;
echo $status->value;

Output:

active

Backed enums provide a from() method to create an enum from its value, and tryFrom() which returns null instead of throwing an error for invalid values:

<?php
$status = Status::from('active');      // Returns Status::Active
$invalid = Status::tryFrom('unknown'); // Returns null

Enums can also contain methods, making them powerful for encapsulating related logic. They work seamlessly with type hints, ensuring your functions only accept valid values - no more checking if a string matches expected options.

challenge icon

Challenge

Easy

Let's build an order management system that uses enums to represent order statuses in a type-safe way. Instead of relying on strings that could be misspelled or invalid, you'll create a backed enum that maps each status to a database-friendly value.

You'll organize your code across three files:

  • OrderStatus.php — Create a string-backed enum called OrderStatus with four cases:
    • Pending backed by 'pending'
    • Processing backed by 'processing'
    • Shipped backed by 'shipped'
    • Delivered backed by 'delivered'
    Add a method label() that returns a human-readable description for each status:
    • Pending returns "Awaiting confirmation"
    • Processing returns "Being prepared"
    • Shipped returns "On the way"
    • Delivered returns "Order complete"
  • Order.php — Create an Order class that uses the enum. Include the OrderStatus file. The class should:
    • Accept an order ID (string) and an OrderStatus in its constructor using constructor promotion
    • Have a method getInfo() that returns "Order [id]: [status label]"
    • Have a method getStatusValue() that returns the backed value of the status (useful for database storage)
  • main.php — Include the Order file. You'll receive two inputs: an order ID and a status string (like "shipped"). Use tryFrom() to safely convert the string input to an OrderStatus enum. If the status is valid, create an Order and print two lines:
    • The result of getInfo()
    • The result of getStatusValue()
    If the status string is invalid, print "Invalid status".

This challenge demonstrates how enums provide type safety — your Order class can only accept valid statuses, and the tryFrom() method lets you safely handle user input without risking invalid values.

Cheat sheet

Enums provide a type-safe way to define a fixed set of values. Define an enum using the enum keyword:

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

$status = Status::Active;
echo $status->name; // Outputs: Active

Backed enums associate string or integer values with each case:

<?php
enum Status: string {
    case Pending = 'pending';
    case Active = 'active';
    case Completed = 'completed';
}

$status = Status::Active;
echo $status->value; // Outputs: active

Use from() to create an enum from its value, or tryFrom() which returns null for invalid values:

<?php
$status = Status::from('active');      // Returns Status::Active
$invalid = Status::tryFrom('unknown'); // Returns null

Enums can contain methods to encapsulate related logic:

<?php
enum Status: string {
    case Pending = 'pending';
    case Active = 'active';
    
    public function label(): string {
        return match($this) {
            self::Pending => 'Awaiting',
            self::Active => 'In Progress',
        };
    }
}

Try it yourself

<?php

require_once 'Order.php';

// Read input
$orderId = trim(fgets(STDIN));
$statusString = trim(fgets(STDIN));

// TODO: Use OrderStatus::tryFrom() to safely convert the status string to an enum
// tryFrom() returns null if the value is invalid

// TODO: If the status is valid, create an Order and print:
// - The result of getInfo()
// - The result of getStatusValue()

// TODO: If the status is invalid, print "Invalid status"

?>
quiz iconTest yourself

This lesson includes a short quiz. Start the lesson to answer it and track your progress.

All lessons in Object Oriented Programming