DEV Community

ahmet gedik
ahmet gedik

Posted on

PHP 8.3 Enums for Video Category Management

PHP 8.3 enums are perfect for managing fixed sets of values like video categories, regions, and cache policies. Here's how I use them in TopVideoHub.

Why Enums?

Before enums, we used string constants:

// 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
Enter fullscreen mode Exit fullscreen mode

With enums:

// 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
Enter fullscreen mode Exit fullscreen mode

Video Categories

YouTube has fixed category IDs. I map them to a PHP enum:

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,
        ];
    }
}
Enter fullscreen mode Exit fullscreen mode

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',
        };
    }
}
Enter fullscreen mode Exit fullscreen mode

Using Enums in Practice

The best part about enums is exhaustive matching. If you add a new region, PHP tells you everywhere you need to handle it:

// 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 * * * *',
    };
}
Enter fullscreen mode Exit fullscreen mode

At TopVideoHub, enums eliminated 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 use them.

Typed Constants (PHP 8.3)

PHP 8.3 added typed constants, which complement enums nicely:

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';
}
Enter fullscreen mode Exit fullscreen mode

These prevent accidentally assigning the wrong type to a constant. Small feature, real bugs prevented.

Top comments (0)