PHP 8.3 Enums for Video Category Management

Published: (March 8, 2026 at 11:00 AM EDT)
4 min read
Source: Dev.to

Source: Dev.to

Using Enums for Categories

Before enums (fragile, no type safety)

// Before: fragile, no type safety
class Categories {
    const MUSIC = 'music';
    const GAMING = 'gaming';
    const ENTERTAINMENT = 'entertainment';
}

function getVideos(string $category): array { /* ... */ }

getVideos('musci'); // Typo compiles fine, fails silently

After enums (type‑safe, IDE support, exhaustive matching)

// After: type-safe, IDE support, exhaustive matching
enum Category: string {
    case Music = 'music';
    case Gaming = 'gaming';
    case Entertainment = 'entertainment';
}

function getVideos(Category $category): array { /* ... */ }

getVideos(Category::Music); // Type-safe

Mapping YouTube Category IDs

enum VideoCategory: int {
    case FilmAnimation   = 1;
    case AutosVehicles   = 2;
    case Music           = 10;
    case PetsAnimals     = 15;
    case Sports          = 17;
    case ShortMovies     = 18;
    case TravelEvents    = 19;
    case Gaming          = 20;
    case Videoblogging   = 21;
    case PeopleBlogs     = 22;
    case Comedy          = 23;
    case Entertainment   = 24;
    case NewsPolitics    = 25;
    case HowtoStyle      = 26;
    case Education       = 27;
    case ScienceTech     = 28;
    case NonprofitsActivism = 29;
    case Movies          = 30;
    case AnimeAnimation  = 31;
    case ActionAdventure = 32;
    case Classics        = 33;
    case Documentary     = 35;
    case Shorts          = 42;

    public function label(): string {
        return match($this) {
            self::FilmAnimation   => 'Film & Animation',
            self::Music           => 'Music',
            self::Gaming          => 'Gaming',
            self::Entertainment   => 'Entertainment',
            self::NewsPolitics    => 'News & Politics',
            self::ScienceTech     => 'Science & Tech',
            self::HowtoStyle      => 'How-to & Style',
            self::Education       => 'Education',
            self::Comedy          => 'Comedy',
            self::Sports          => 'Sports',
            self::PeopleBlogs     => 'People & Blogs',
            default                => $this->name,
        };
    }

    public function slug(): string {
        return strtolower(preg_replace('/[^a-z0-9]+/i', '-', $this->label()));
    }

    public function icon(): string {
        return match($this) {
            self::Music           => 'music-note',
            self::Gaming          => 'gamepad',
            self::Entertainment   => 'star',
            self::NewsPolitics    => 'newspaper',
            self::ScienceTech     => 'flask',
            self::Sports          => 'trophy',
            default                => 'play-circle',
        };
    }

    /**
     * Categories displayed in the navigation bar.
     */
    public static function navCategories(): array {
        return [
            self::Music,
            self::Gaming,
            self::Entertainment,
            self::NewsPolitics,
            self::ScienceTech,
            self::Sports,
            self::HowtoStyle,
            self::Education,
            self::Comedy,
            self::PeopleBlogs,
        ];
    }
}

Region Enum

enum Region: string {
    case US = 'US';
    case GB = 'GB';
    case JP = 'JP';
    case KR = 'KR';
    case TW = 'TW';
    case SG = 'SG';
    case VN = 'VN';
    case TH = 'TH';
    case HK = 'HK';

    public function label(): string {
        return match($this) {
            self::US => 'United States',
            self::GB => 'United Kingdom',
            self::JP => 'Japan',
            self::KR => 'South Korea',
            self::TW => 'Taiwan',
            self::SG => 'Singapore',
            self::VN => 'Vietnam',
            self::TH => 'Thailand',
            self::HK => 'Hong Kong',
        };
    }

    public function flag(): string {
        // Convert country code to flag emoji
        $chars = str_split($this->value);
        return implode('', array_map(
            fn(string $c) => mb_chr(ord($c) - ord('A') + 0x1F1E6),
            $chars
        ));
    }

    public function hreflang(): string {
        return match($this) {
            self::JP => 'ja',
            self::KR => 'ko',
            self::TW => 'zh-TW',
            self::HK => 'zh-HK',
            self::VN => 'vi',
            self::TH => 'th',
            default  => 'en',
        };
    }
}

Exhaustive Matching Example

// This match is exhaustive — add a new Region case
// and PHP warns you about every unhandled match
function cronInterval(Region $region): string {
    return match($region) {
        Region::US, Region::GB => '*/2 * * * *',
        Region::JP, Region::KR => '*/3 * * * *',
        Region::TW, Region::SG, Region::HK => '*/4 * * * *',
        Region::VN, Region::TH => '*/6 * * * *',
    };
}

Typed Constants for Cache Configuration

class CacheConfig {
    const int    HOME_TTL     = 10800;
    const int    WATCH_TTL    = 21600;
    const int    SEARCH_TTL   = 600;
    const int    CATEGORY_TTL = 86400;
    const string CACHE_DIR    = 'data/pagecache';
}

Typed constants complement enums nicely, preventing accidental type mismatches and eliminating an entire class of bugs—typos in region codes, invalid category IDs, and misconfigured cache policies. If you’re on PHP 8.1+, there’s no reason not to adopt them.

0 views
Back to Blog

Related posts

Read more »