From 7c26f056fc4606a466e4c2599d587e3b9bc44274 Mon Sep 17 00:00:00 2001 From: Alex Standiford Date: Sun, 25 Jan 2026 12:26:00 -0500 Subject: [PATCH] Add enum-polyfill package documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Documents the phpnomad/enum-polyfill package, which provides an enum trait for PHP versions that don't have native enum support. Includes: - Enum trait with from() and tryFrom() methods - Usage examples and best practices πŸ€– Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .../packages/enum-polyfill/introduction.md | 295 ++++++++++++ .../packages/enum-polyfill/traits/enum.md | 429 ++++++++++++++++++ .../enum-polyfill/traits/introduction.md | 86 ++++ 3 files changed, 810 insertions(+) create mode 100644 public/docs/packages/enum-polyfill/introduction.md create mode 100644 public/docs/packages/enum-polyfill/traits/enum.md create mode 100644 public/docs/packages/enum-polyfill/traits/introduction.md diff --git a/public/docs/packages/enum-polyfill/introduction.md b/public/docs/packages/enum-polyfill/introduction.md new file mode 100644 index 0000000..db1ec82 --- /dev/null +++ b/public/docs/packages/enum-polyfill/introduction.md @@ -0,0 +1,295 @@ +--- +id: enum-polyfill-introduction +slug: docs/packages/enum-polyfill/introduction +title: Enum Polyfill Package +doc_type: explanation +status: active +language: en +owner: docs-team +last_reviewed: 2026-01-25 +applies_to: ["all"] +canonical: true +summary: The enum-polyfill package provides PHP 8.1-style enum methods to regular classes using constants, enabling backward-compatible enum functionality. +llm_summary: > + phpnomad/enum-polyfill provides the Enum trait that gives PHP classes enum-like behavior using + class constants. It provides methods matching PHP 8.1's native enum API: cases(), from(), + tryFrom(), getValues(), and isValid(). The trait uses singleton pattern (via WithInstance) to + cache reflection results for performance. Classes using this trait define constants as enum + values and get automatic validation, iteration, and safe value retrieval. Commonly used for + HTTP methods, CRUD action types, session contexts, and other fixed sets of values. Works on + PHP 7.4+ and provides forward-compatible syntax for projects targeting older PHP versions. +questions_answered: + - What is the enum-polyfill package? + - How do I create enums in PHPNomad for older PHP versions? + - When should I use enum-polyfill vs native PHP enums? +audience: + - developers + - backend engineers +tags: + - enum + - polyfill + - trait + - backward-compatibility +llm_tags: + - enum-trait + - cases-method + - from-method + - tryFrom-method + - php-compatibility +keywords: + - phpnomad enum + - php enum polyfill + - enum trait php + - backward compatible enum + - php 7.4 enum +related: + - ../singleton/introduction + - ../auth/introduction + - ../http/introduction +see_also: + - ../cache/introduction + - ../rest/introduction +noindex: false +--- + +# Enum Polyfill + +`phpnomad/enum-polyfill` provides **PHP 8.1-style enum functionality for older PHP versions**. It consists of a single traitβ€”`Enum`β€”that can be added to any class with constants to gain enum-like behavior. + +At its core: + +* **API compatibility** β€” Methods match PHP 8.1's native enum API (`cases()`, `from()`, `tryFrom()`) +* **Validation** β€” Check if values are valid enum members with `isValid()` +* **Performance** β€” Reflection results cached via singleton pattern +* **Zero migration path** β€” When upgrading to PHP 8.1+, switch to native enums with minimal changes + +--- + +## Key ideas at a glance + +| Component | Purpose | +|-----------|---------| +| [Enum trait](./traits/enum.md) | Add to any class with constants to get enum behavior | +| `cases()` / `getValues()` | Returns all possible enum values | +| `from($value)` | Gets value or throws exception if invalid | +| `tryFrom($value)` | Gets value or returns null if invalid | +| `isValid($value)` | Check if a value is a valid enum member | + +--- + +## Why this package exists + +PHP 8.1 introduced native enums, but many projects still support older PHP versions. Without a polyfill, developers must: + +| Problem | Without enum-polyfill | With enum-polyfill | +|---------|----------------------|-------------------| +| Validation | Write custom validation per "enum" | `Status::isValid($value)` | +| Listing values | Manual array or reflection | `Status::cases()` | +| Safe retrieval | Custom try/catch everywhere | `Status::tryFrom($value)` | +| Migration path | Rewrite when upgrading PHP | Swap trait for native enum | + +This package provides a **forward-compatible API** that mirrors PHP 8.1 enums, making future migration straightforward. + +--- + +## Installation + +```bash +composer require phpnomad/enum-polyfill +``` + +**Requirements:** PHP 7.4+ + +**Dependencies:** `phpnomad/singleton` + +--- + +## Basic usage + +Define a class with constants and add the trait: + +```php +use PHPNomad\Enum\Traits\Enum; + +class Status +{ + use Enum; + + public const Active = 'active'; + public const Pending = 'pending'; + public const Inactive = 'inactive'; +} +``` + +Now use it like a PHP 8.1 enum: + +```php +// Get all possible values +$statuses = Status::cases(); +// ['active', 'pending', 'inactive'] + +// Validate a value +if (Status::isValid($userInput)) { + // Safe to use +} + +// Get value or null +$status = Status::tryFrom($userInput); +if ($status !== null) { + // Valid value +} + +// Get value or throw exception +try { + $status = Status::from($userInput); +} catch (UnexpectedValueException $e) { + // Invalid value +} +``` + +See [Enum trait](./traits/enum.md) for complete API documentation. + +--- + +## When to use this package + +| Scenario | Recommendation | +|----------|---------------| +| PHP 7.4 / 8.0 project | Use enum-polyfill | +| PHP 8.1+ project | Consider native enums | +| Library supporting PHP 7.4+ | Use enum-polyfill for compatibility | +| Need custom enum methods | Use enum-polyfill (more flexible than native) | +| Strict type safety needed | Native PHP 8.1 enums are stronger | + +### Advantages over native enums + +* Works on PHP 7.4+ +* Can add arbitrary methods to enum classes +* Constant values can be any type + +### Advantages of native enums + +* True type safety (function accepts `Status`, not `string`) +* Better IDE support +* Pattern matching with `match` expressions +* Built into the language + +--- + +## When NOT to use this package + +### You're on PHP 8.1+ exclusively + +If you don't need to support older PHP versions, native enums are cleaner: + +```php +// Native PHP 8.1 enum +enum Status: string +{ + case Active = 'active'; + case Pending = 'pending'; + case Inactive = 'inactive'; +} + +// Type-safe function +function setStatus(Status $status): void +{ + // $status is guaranteed to be a valid Status +} + +setStatus(Status::Active); // OK +setStatus('active'); // Error - type mismatch +``` + +### You need true type safety + +The polyfill returns the constant values (strings, integers, etc.), not typed objects: + +```php +// With polyfill - no type safety +function setStatus(string $status): void +{ + if (!Status::isValid($status)) { + throw new InvalidArgumentException(); + } +} + +setStatus('typo'); // Compiles fine, fails at runtime +``` + +--- + +## Package contents + +### Traits + +| Trait | Description | +|-------|-------------| +| [Enum](./traits/enum.md) | Provides enum-like behavior to classes with constants | + +See [Traits Overview](./traits/introduction.md) for details. + +--- + +## Migration to native enums + +When you upgrade to PHP 8.1+, converting is straightforward: + +```php +// Before (polyfill) +use PHPNomad\Enum\Traits\Enum; + +class Status +{ + use Enum; + + public const Active = 'active'; + public const Pending = 'pending'; + public const Inactive = 'inactive'; +} + +$status = Status::from('active'); // 'active' +``` + +```php +// After (native) +enum Status: string +{ + case Active = 'active'; + case Pending = 'pending'; + case Inactive = 'inactive'; +} + +$status = Status::from('active'); // Status::Active +``` + +The main difference: native enums return enum instances, while the polyfill returns the raw values. Update call sites accordingly. + +--- + +## Relationship to other packages + +### Dependencies + +| Package | Relationship | +|---------|-------------| +| [singleton](../singleton/introduction.md) | Uses `WithInstance` trait for caching | + +### Packages that use enum-polyfill + +| Package | How it uses enum-polyfill | +|---------|--------------------------| +| [auth](../auth/introduction.md) | `ActionTypes`, `SessionContexts` enums | +| [http](../http/introduction.md) | `Method` enum for HTTP verbs | +| [cache](../cache/introduction.md) | `Operation` enum for CRUD operations | +| [rest](../rest/introduction.md) | `BasicTypes` enum | +| wordpress-plugin | Various status and type enums | + +--- + +## Next steps + +* **[Enum Trait](./traits/enum.md)** β€” Complete API reference +* **[Singleton Package](../singleton/introduction.md)** β€” Understand the caching mechanism +* **[HTTP Package](../http/introduction.md)** β€” See Method enum in action +* **[Auth Package](../auth/introduction.md)** β€” See ActionTypes enum diff --git a/public/docs/packages/enum-polyfill/traits/enum.md b/public/docs/packages/enum-polyfill/traits/enum.md new file mode 100644 index 0000000..65a3ddc --- /dev/null +++ b/public/docs/packages/enum-polyfill/traits/enum.md @@ -0,0 +1,429 @@ +--- +id: enum-trait +slug: docs/packages/enum-polyfill/traits/enum +title: Enum Trait +doc_type: reference +status: active +language: en +owner: docs-team +last_reviewed: 2026-01-25 +applies_to: ["all"] +canonical: true +summary: The Enum trait provides PHP 8.1-style enum methods to classes using constants. +llm_summary: > + The Enum trait from phpnomad/enum-polyfill gives PHP classes enum-like behavior using + class constants. It provides methods matching PHP 8.1's native enum API: cases(), from(), + tryFrom(), getValues(), and isValid(). The trait uses singleton pattern (via WithInstance) + to cache reflection results for performance. Classes using this trait define constants as + enum values and get automatic validation, iteration, and safe value retrieval. +questions_answered: + - How does the Enum trait work? + - What methods does the Enum trait provide? + - What is the difference between from() and tryFrom()? + - How do I validate a value against an enum? + - How do I get all enum values? + - Can I add custom methods to enum classes? +audience: + - developers + - backend engineers +tags: + - enum + - trait + - polyfill + - backward-compatibility +llm_tags: + - enum-trait + - cases-method + - from-method + - tryFrom-method +keywords: + - Enum trait + - php enum + - cases method + - from method + - tryFrom method +related: + - ../introduction + - ../../singleton/introduction +see_also: + - ../../auth/introduction + - ../../http/introduction +noindex: false +--- + +# Enum Trait + +**Namespace:** `PHPNomad\Enum\Traits` + +The `Enum` trait adds PHP 8.1-style enum functionality to any class with constants. Add this trait to gain `cases()`, `from()`, `tryFrom()`, and `isValid()` methods. + +--- + +## How It Works + +The trait uses reflection to read class constants and provides methods to work with them: + +``` +β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” +β”‚ class Status { use Enum; const Active = 'active'; ... } β”‚ +β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ + β–Ό + β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” + β”‚ First call to cases()/from() β”‚ + β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ + β–Ό + β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” + β”‚ Reflection reads constants β”‚ + β”‚ ['Active' => 'active', ...] β”‚ + β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ + β–Ό + β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” + β”‚ Values cached in singleton β”‚ + β”‚ (via WithInstance trait) β”‚ + β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ + β”‚ + β–Ό + β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” + β”‚ Subsequent calls use cache β”‚ + β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ +``` + +The singleton pattern ensures reflection only runs once per class, regardless of how many times you call enum methods. + +--- + +## Methods + +### cases() + +Returns all enum values as an array. + +```php +public static function cases(): array +``` + +**Returns:** Array of all constant values + +**Example:** + +```php +class Status +{ + use Enum; + + public const Active = 'active'; + public const Pending = 'pending'; + public const Inactive = 'inactive'; +} + +$statuses = Status::cases(); +// ['active', 'pending', 'inactive'] +``` + +--- + +### getValues() + +Alias for `cases()`. Returns all enum values. + +```php +public static function getValues(): array +``` + +**Returns:** Array of all constant values + +--- + +### isValid() + +Checks if a value is a valid enum member. + +```php +public static function isValid($value): bool +``` + +| Parameter | Type | Description | +|-----------|------|-------------| +| `$value` | `mixed` | The value to check | + +**Returns:** `true` if value matches a constant, `false` otherwise + +**Note:** Uses strict comparison (`===`) + +**Example:** + +```php +Status::isValid('active'); // true +Status::isValid('invalid'); // false +Status::isValid(null); // false +``` + +--- + +### from() + +Returns the value if valid, throws exception if not. + +```php +public static function from($value): mixed +``` + +| Parameter | Type | Description | +|-----------|------|-------------| +| `$value` | `mixed` | The value to validate and return | + +**Returns:** The value if it's a valid enum member + +**Throws:** `UnexpectedValueException` if value is not valid + +**Example:** + +```php +$status = Status::from('active'); // 'active' +$status = Status::from('invalid'); // throws UnexpectedValueException +``` + +**Use for:** Internal code where invalid values indicate bugs + +--- + +### tryFrom() + +Returns the value if valid, `null` if not. + +```php +public static function tryFrom($value): mixed|null +``` + +| Parameter | Type | Description | +|-----------|------|-------------| +| `$value` | `mixed` | The value to validate and return | + +**Returns:** The value if valid, `null` if not + +**Example:** + +```php +$status = Status::tryFrom('active'); // 'active' +$status = Status::tryFrom('invalid'); // null +``` + +**Use for:** User input where invalid values are expected + +--- + +## Basic Usage + +Define a class with constants and add the trait: + +```php +use PHPNomad\Enum\Traits\Enum; + +class Status +{ + use Enum; + + public const Active = 'active'; + public const Pending = 'pending'; + public const Inactive = 'inactive'; +} +``` + +Now use it like a PHP 8.1 enum: + +```php +// Get all possible values +$statuses = Status::cases(); +// ['active', 'pending', 'inactive'] + +// Validate a value +if (Status::isValid($userInput)) { + // Safe to use +} + +// Get value or null +$status = Status::tryFrom($userInput); +if ($status !== null) { + // Valid value +} + +// Get value or throw exception +try { + $status = Status::from($userInput); +} catch (UnexpectedValueException $e) { + // Invalid value +} +``` + +--- + +## Real-World Examples + +### HTTP Methods (from phpnomad/http) + +```php +use PHPNomad\Enum\Traits\Enum; + +class Method +{ + use Enum; + + public const Get = 'GET'; + public const Post = 'POST'; + public const Put = 'PUT'; + public const Delete = 'DELETE'; + public const Patch = 'PATCH'; + public const Options = 'OPTIONS'; +} + +// Usage in a router +function registerRoute(string $method, string $path, callable $handler): void +{ + if (!Method::isValid($method)) { + throw new InvalidArgumentException("Invalid HTTP method: {$method}"); + } + // Register route... +} + +registerRoute(Method::Get, '/users', $listUsers); +registerRoute(Method::Post, '/users', $createUser); +``` + +### CRUD Action Types (from phpnomad/auth) + +```php +use PHPNomad\Enum\Traits\Enum; + +class ActionTypes +{ + use Enum; + + public const Create = 'create'; + public const Read = 'read'; + public const Update = 'update'; + public const Delete = 'delete'; +} + +// Usage in permission checking +function canPerformAction(User $user, string $action, Resource $resource): bool +{ + $action = ActionTypes::from($action); // Validates the action + return $user->hasPermission($action, $resource); +} +``` + +--- + +## Adding Custom Methods + +Unlike native PHP enums (which have limitations), classes using the Enum trait are regular PHP classesβ€”you can add any methods you need: + +```php +use PHPNomad\Enum\Traits\Enum; + +class Priority +{ + use Enum; + + public const Low = 1; + public const Medium = 2; + public const High = 3; + public const Critical = 4; + + /** + * Get human-readable label + */ + public static function getLabel(int $priority): string + { + return match ($priority) { + self::Low => 'Low Priority', + self::Medium => 'Medium Priority', + self::High => 'High Priority', + self::Critical => 'Critical', + default => 'Unknown', + }; + } + + /** + * Check if priority is urgent + */ + public static function isUrgent(int $priority): bool + { + return $priority >= self::High; + } +} +``` + +--- + +## Behavior Notes + +| Aspect | Behavior | +|--------|----------| +| Comparison | `isValid()` uses strict type checking (`===`) | +| Caching | Reflection results cached after first access | +| Return values | Returns constant values, not constant names | +| Dependencies | Uses `WithInstance` from singleton package | + +--- + +## Best Practices + +### Use from() for internal code, tryFrom() for user input + +```php +// Internal code - throw on invalid (indicates bug) +$method = Method::from($routeConfig['method']); + +// User input - handle gracefully +$status = Status::tryFrom($userInput); +if ($status === null) { + // Show error to user +} +``` + +### Validate at system boundaries + +```php +class UserController +{ + public function updateStatus(Request $request): Response + { + $status = Status::tryFrom($request->get('status')); + + if ($status === null) { + return Response::badRequest('Invalid status'); + } + + // Safe to use $status + $this->userService->setStatus($userId, $status); + } +} +``` + +### Use meaningful constant names and values + +```php +// Good - clear names, consistent values +class HttpStatus +{ + use Enum; + + public const Ok = 200; + public const Created = 201; + public const BadRequest = 400; + public const NotFound = 404; +} +``` + +--- + +## See Also + +- [Enum Polyfill Package Overview](../introduction.md) - High-level documentation +- [Singleton Package](../../singleton/introduction.md) - Provides caching mechanism +- [Auth Package](../../auth/introduction.md) - Uses ActionTypes enum +- [HTTP Package](../../http/introduction.md) - Uses Method enum diff --git a/public/docs/packages/enum-polyfill/traits/introduction.md b/public/docs/packages/enum-polyfill/traits/introduction.md new file mode 100644 index 0000000..945b197 --- /dev/null +++ b/public/docs/packages/enum-polyfill/traits/introduction.md @@ -0,0 +1,86 @@ +--- +id: enum-polyfill-traits-introduction +slug: docs/packages/enum-polyfill/traits/introduction +title: Enum Polyfill Traits Overview +doc_type: reference +status: active +language: en +owner: docs-team +last_reviewed: 2026-01-25 +applies_to: ["all"] +canonical: true +summary: Overview of traits provided by the enum-polyfill package. +llm_summary: > + The phpnomad/enum-polyfill package provides one trait: Enum, which gives any PHP class with + constants enum-like behavior including cases(), from(), tryFrom(), and isValid() methods. + This enables PHP 8.1-style enum functionality on older PHP versions. +questions_answered: + - What traits does the enum-polyfill package provide? + - What is the Enum trait? +audience: + - developers + - backend engineers +tags: + - enum + - traits + - reference +llm_tags: + - enum-trait + - php-compatibility +keywords: + - enum traits + - Enum trait +related: + - ../introduction + - ./enum +see_also: + - ../../singleton/introduction +noindex: false +--- + +# Enum Polyfill Traits + +The enum-polyfill package provides one trait that enables PHP 8.1-style enum functionality on older PHP versions. + +--- + +## Available Traits + +| Trait | Purpose | +|-------|---------| +| [Enum](./enum.md) | Adds enum-like behavior to classes with constants | + +--- + +## Quick Reference + +### Enum Trait + +Adds `cases()`, `from()`, `tryFrom()`, and `isValid()` methods to any class: + +```php +use PHPNomad\Enum\Traits\Enum; + +class Status +{ + use Enum; + + public const Active = 'active'; + public const Pending = 'pending'; + public const Inactive = 'inactive'; +} + +// Now use it like a PHP 8.1 enum +$statuses = Status::cases(); // ['active', 'pending', 'inactive'] +$isValid = Status::isValid('active'); // true +$status = Status::tryFrom('invalid'); // null +``` + +See [Enum](./enum.md) for complete documentation. + +--- + +## See Also + +- [Enum Polyfill Package Overview](../introduction.md) - High-level package documentation +- [Singleton Package](../../singleton/introduction.md) - The Enum trait uses singleton for caching