philiprehberger/php-enum-utils

Utility trait and helpers for PHP 8.1+ native enums

Maintainers

Package info

github.com/philiprehberger/php-enum-utils

pkg:composer/philiprehberger/php-enum-utils

Fund package maintenance!

philiprehberger

Statistics

Installs: 38

Dependents: 0

Suggesters: 0

Stars: 1

Open Issues: 0

v1.2.0 2026-04-01 13:40 UTC

This package is auto-updated.

Last update: 2026-04-22 16:00:34 UTC


README

Tests Latest Version on Packagist Last updated

Utility trait and helpers for PHP 8.1+ native enums.

Requirements

  • PHP 8.2+

Installation

composer require philiprehberger/php-enum-utils

Usage

Adding the trait to your enum

use PhilipRehberger\EnumUtils\EnumUtils;
use PhilipRehberger\EnumUtils\Attributes\Label;
use PhilipRehberger\EnumUtils\Attributes\Description;

enum Status: string
{
    use EnumUtils;

    #[Label('Pending Review')]
    #[Description('The item is waiting for review')]
    case Pending = 'pending';

    #[Label('In Progress')]
    case InProgress = 'in_progress';

    case Completed = 'completed';
}

Lookup by name

$case = Status::fromName('pending');      // Status::Pending (case-insensitive)
$case = Status::tryFromName('unknown');   // null

Listing cases

Status::names();   // ['Pending', 'InProgress', 'Completed']
Status::values();  // ['pending', 'in_progress', 'completed']
Status::count();   // 3

Arrays for forms and selects

Status::toSelectArray();
// ['pending' => 'Pending Review', 'in_progress' => 'In Progress', 'completed' => 'Completed']

Status::toArray();
// ['Pending' => 'pending', 'InProgress' => 'in_progress', 'Completed' => 'completed']

Filtering cases

// Filter by a custom predicate
$active = Status::casesWhere(fn (Status $s) => $s !== Status::Completed);
// [Status::Pending, Status::InProgress]

// Check if a case is among a given set
Status::Pending->in(Status::Pending, Status::InProgress);   // true
Status::Completed->in(Status::Pending, Status::InProgress); // false

Random case and comparison

$case = Status::random();                        // A random Status case
Status::Pending->equals(Status::Pending);        // true
Status::Pending->equals(Status::Completed);      // false

Collections

use PhilipRehberger\EnumUtils\EnumCollection;

// Wrap all cases in a fluent collection
$active = Status::collect()
    ->filter(fn (Status $s) => $s !== Status::Completed)
    ->sortBy(fn (Status $s) => $s->value)
    ->toArray();

// Get the first matching case
$first = Status::collect()->first(fn (Status $s) => str_starts_with($s->value, 'p'));

// Group cases
$grouped = Status::collect()->groupBy(fn (Status $s) => $s === Status::Completed ? 'done' : 'active');

// Partition into two arrays: [matching, non-matching]
[$pending, $rest] = Status::collect()->partition(fn (Status $s) => $s === Status::Pending);

Serialization

// Serialize all cases to JSON
$json = Status::toJson();
// [{"name":"Pending","value":"pending","label":"Pending Review","description":"..."},...]

// Deserialize back to enum cases
$cases = Status::fromJson($json);  // [Status::Pending, Status::InProgress, ...]

// Get value => label map
$map = Status::toMap();
// ['pending' => 'Pending Review', 'in_progress' => 'In Progress', 'completed' => 'Completed']

State Transitions

use PhilipRehberger\EnumUtils\Attributes\AllowedTransitions;

enum OrderStatus: string
{
    use EnumUtils;

    #[AllowedTransitions(self::Processing, self::Cancelled)]
    case Pending = 'pending';

    #[AllowedTransitions(self::Shipped, self::Cancelled)]
    case Processing = 'processing';

    #[AllowedTransitions(self::Delivered)]
    case Shipped = 'shipped';

    case Delivered = 'delivered';
    case Cancelled = 'cancelled';
}

OrderStatus::Pending->canTransitionTo(OrderStatus::Processing);  // true
OrderStatus::Pending->canTransitionTo(OrderStatus::Shipped);     // false
OrderStatus::Pending->allowedTransitions();  // [OrderStatus::Processing, OrderStatus::Cancelled]
OrderStatus::Delivered->allowedTransitions(); // [] (no transitions defined)

Reading attributes with EnumMeta

use PhilipRehberger\EnumUtils\EnumMeta;

EnumMeta::label(Status::Pending);         // 'Pending Review'
EnumMeta::label(Status::Completed);       // 'Completed' (fallback: humanized name)
EnumMeta::description(Status::Pending);   // 'The item is waiting for review'
EnumMeta::description(Status::Completed); // null
EnumMeta::labels(Status::class);          // ['pending' => 'Pending Review', ...]

API

EnumUtils Trait

Method Description
::fromName(string $name): static Case-insensitive lookup by name; throws ValueError on miss
::tryFromName(string $name): ?static Case-insensitive lookup by name; returns null on miss
::names(): array All case names as a flat array
::values(): array All case values as a flat array
::random(): static A random case
::casesWhere(callable $filter): array Filter cases by a custom predicate
::toSelectArray(): array [value => label] for form selects
::toArray(): array [name => value] for serialization
::count(): int Total number of cases
->equals(self $other): bool Strict identity comparison
->in(self ...$cases): bool Check if case is among the given set
::collect(): EnumCollection Wrap all cases in a fluent collection
::toJson(): string Serialize all cases to JSON
::fromJson(string $json): array Deserialize JSON back to enum cases
::toMap(): array [value => label] map for all cases
->canTransitionTo(self $target): bool Check if transition is allowed
->allowedTransitions(): array Get all allowed target states

EnumMeta Helper

Method Description
EnumMeta::label(BackedEnum $case): string Label from attribute or humanized name
EnumMeta::description(BackedEnum $case): ?string Description from attribute or null
EnumMeta::labels(string $enumClass): array [value => label] for all cases

Attributes

Attribute Target Purpose
#[Label('...')] Enum case Human-readable label
#[Description('...')] Enum case Longer description text
#[AllowedTransitions(...)] Enum case Define valid state transitions

Development

composer install
vendor/bin/phpunit
vendor/bin/pint --test
vendor/bin/phpstan analyse

Support

If you find this project useful:

Star the repo

🐛 Report issues

💡 Suggest features

❤️ Sponsor development

🌐 All Open Source Projects

💻 GitHub Profile

🔗 LinkedIn Profile

License

MIT