Ergonomic utilities for PHP enums, including names, values, lookups, and option maps.

v0.1.0 2026-04-24 22:56 UTC

This package is auto-updated.

Last update: 2026-04-24 22:57:37 UTC


README

Ergonomic utilities and reusable catalogs for PHP enums, including names, values, lookups, maps, sorting helpers, and enum-driven workflows.

PHP Version Composer Package Tests Coverage Docs License GitHub Sponsors

Fast Forward Enum mascot banner

โœจ Features

  • ๐Ÿงฉ Traits for values(), names(), options, maps, lookups, and enum comparisons
  • ๐Ÿงญ Helper\EnumHelper for generic operations over UnitEnum and BackedEnum
  • ๐Ÿ”„ Reversible sort-oriented enums such as SortDirection, NullsPosition, and ComparisonResult
  • ๐Ÿ—‚ Reusable catalogs grouped by domain, including Calendar, Logger, Runtime, and DateTime
  • ๐Ÿšฆ Enum-based workflow transitions through StateMachine\HasTransitions
  • ๐Ÿท Optional LabeledEnumInterface and readable descriptions without framework lock-in
  • ๐Ÿงผ Small public API with explicit namespaces and no Contracts bucket

๐Ÿ“ฆ Installation

composer require fast-forward/enum

Requirements:

  • PHP ^8.3

New to the package? Start with the Quickstart, then use the Usage guide when you want more complete examples.

๐Ÿ› ๏ธ Usage

Basic enum ergonomics:

<?php

declare(strict_types=1);

use FastForward\Enum\Helper\EnumHelper;
use FastForward\Enum\Trait\Comparable;
use FastForward\Enum\Trait\HasDescription;
use FastForward\Enum\Trait\HasNameLookup;
use FastForward\Enum\Trait\HasNames;
use FastForward\Enum\Trait\HasOptions;
use FastForward\Enum\Trait\HasValues;

enum Status: string
{
    use Comparable;
    use HasDescription;
    use HasNameLookup;
    use HasNames;
    use HasOptions;
    use HasValues;

    case Draft = 'draft';
    case Published = 'published';
}

Status::values(); // ['draft', 'published']
Status::names(); // ['Draft', 'Published']
Status::options(); // ['Draft' => 'draft', 'Published' => 'published']
Status::fromName('Draft'); // Status::Draft
Status::Draft->is(Status::Published); // false
Status::Draft->description(); // 'Draft'

EnumHelper::valueMap(Status::class); // ['draft' => Status::Draft, 'published' => Status::Published]

Labels and label maps:

<?php

declare(strict_types=1);

use FastForward\Enum\Helper\EnumHelper;
use FastForward\Enum\LabeledEnumInterface;

enum Priority: int implements LabeledEnumInterface
{
    case Low = 1;
    case High = 2;

    public function label(): string
    {
        return match ($this) {
            self::Low => 'Low priority',
            self::High => 'High priority',
        };
    }
}

EnumHelper::labels(Priority::class); // ['Low priority', 'High priority']
EnumHelper::labelMap(Priority::class); // ['Low' => 'Low priority', 'High' => 'High priority']

Enum-driven workflows:

<?php

declare(strict_types=1);

use FastForward\Enum\StateMachine\HasTransitions;
use FastForward\Enum\StateMachine\InvalidTransitionException;

enum ArticleWorkflow: string
{
    use HasTransitions;

    case Draft = 'draft';
    case Reviewing = 'reviewing';
    case Published = 'published';
    case Archived = 'archived';

    protected static function transitionMap(): array
    {
        return [
            self::Draft->name => [self::Reviewing, self::Archived],
            self::Reviewing->name => [self::Published, self::Draft],
            self::Published->name => [self::Archived],
            self::Archived->name => [],
        ];
    }

    protected static function initialStateCases(): array
    {
        return [self::Draft];
    }
}

ArticleWorkflow::Draft->canTransitionTo(ArticleWorkflow::Reviewing); // true
ArticleWorkflow::Archived->isTerminal(); // true
ArticleWorkflow::initialStates(); // [ArticleWorkflow::Draft]

try {
    ArticleWorkflow::Reviewing->assertCanTransitionTo(ArticleWorkflow::Archived);
} catch (InvalidTransitionException $exception) {
    // Invalid transition
}

Packaged enum catalogs:

<?php

declare(strict_types=1);

use FastForward\Enum\Calendar\Month;
use FastForward\Enum\Calendar\Quarter;
use FastForward\Enum\Calendar\Semester;
use FastForward\Enum\Calendar\Weekday;
use FastForward\Enum\Common\Priority;
use FastForward\Enum\Common\Severity;
use FastForward\Enum\Comparison\ComparisonOperator;
use FastForward\Enum\Container\ServiceLifetime;
use FastForward\Enum\DateTime\IntervalUnit;
use FastForward\Enum\Event\DispatchMode;
use FastForward\Enum\Http\Scheme;
use FastForward\Enum\Logger\LogLevel;
use FastForward\Enum\Outcome\Result;
use FastForward\Enum\Pipeline\FailureMode;
use FastForward\Enum\Process\SignalBehavior;
use FastForward\Enum\Runtime\Environment;
use FastForward\Enum\Sort\CaseSensitivity;
use FastForward\Enum\Sort\ComparisonResult;
use FastForward\Enum\Sort\NullsPosition;
use FastForward\Enum\Sort\SortDirection;

Environment::Production->isProduction(); // true
Priority::Critical->isHigherThan(Priority::Normal); // true
Severity::Error->isAtLeast(Severity::Warning); // true
LogLevel::Critical->isAtLeast(LogLevel::Warning); // true
Result::Partial->isSuccessful(); // true
ComparisonOperator::In->compare('draft', ['draft', 'published']); // true
IntervalUnit::Hour->seconds(2); // 7200
DispatchMode::Async->isAsync(); // true
ServiceLifetime::Singleton->isReusable(); // true
FailureMode::StopOnFailure->stopsOnFailure(); // true
Scheme::Https->defaultPort(); // 443
SignalBehavior::Handle->isTerminalControl(); // true
Weekday::Saturday->isWeekend(); // true
Month::December->quarter(); // 4
Quarter::Q2->months(); // [Month::April, Month::May, Month::June]
Semester::H2->quarters(); // [Quarter::Q3, Quarter::Q4]
SortDirection::Descending->reverse(); // SortDirection::Ascending
NullsPosition::Last->compareNullability(null, 'value'); // 1
CaseSensitivity::Insensitive->equals('Draft', 'draft'); // true
ComparisonResult::fromComparisonResult(-1); // ComparisonResult::RightGreater

๐Ÿงฐ API Summary

API Description
Helper\EnumHelper Static helpers for cases, names, values, labels, maps, and lookups
Trait\HasValues Adds values() to backed enums
Trait\HasNames Adds names() to any enum
Trait\HasNameLookup Adds fromName(), tryFromName(), and hasName()
Trait\HasOptions Builds option arrays keyed by case name
Trait\HasNameMap / Trait\HasValueMap Builds lookup maps for names and backed values
Trait\Comparable Adds is(), isNot(), in(), and notIn()
Trait\HasDescription Generates readable descriptions from case names
Trait\HasLabel Provides a technical fallback label() implementation
LabeledEnumInterface Contract for enums that expose presentation labels
DescribedEnumInterface Contract for enums that expose human-readable descriptions
ReversibleInterface Common contract for enums exposing reverse()
StateMachine\HasTransitions Adds transition, terminal, and initial-state behavior to workflow enums
StateMachine\InvalidTransitionException Exception thrown by invalid workflow transitions

๐Ÿ”Œ Integration

fast-forward/enum is framework-agnostic and works well in:

  • form and UI option generation
  • DTO, request, and serializer layers
  • validation and name/value normalization
  • internal workflow modeling with enum transitions
  • logging, sorting, date/time, and runtime catalogs shared across Fast Forward packages

It does not require a container, framework bridge, or reflection-heavy metadata system.

๐Ÿ“ Directory Structure Example

src/
โ”œโ”€โ”€ Calendar/
โ”œโ”€โ”€ Common/
โ”œโ”€โ”€ Comparison/
โ”œโ”€โ”€ Container/
โ”œโ”€โ”€ DateTime/
โ”œโ”€โ”€ Event/
โ”œโ”€โ”€ Helper/
โ”œโ”€โ”€ Http/
โ”œโ”€โ”€ Logger/
โ”œโ”€โ”€ Outcome/
โ”œโ”€โ”€ Pipeline/
โ”œโ”€โ”€ Process/
โ”œโ”€โ”€ Runtime/
โ”œโ”€โ”€ Sort/
โ”œโ”€โ”€ StateMachine/
โ””โ”€โ”€ Trait/
tests/
โ”œโ”€โ”€ Common/
โ”œโ”€โ”€ Helper/
โ”œโ”€โ”€ Sort/
โ”œโ”€โ”€ StateMachine/
โ”œโ”€โ”€ Support/
โ””โ”€โ”€ Trait/
docs/
โ”œโ”€โ”€ getting-started/
โ”œโ”€โ”€ usage/
โ”œโ”€โ”€ api/
โ””โ”€โ”€ advanced/

โš™๏ธ Advanced & Customization

  • Implement LabeledEnumInterface when you need explicit presentation labels.
  • Use your own domain enums when semantics are business-specific rather than generic.
  • Combine Comparable, lookup traits, and HasTransitions to build compact workflow models.
  • Prefer the packaged catalogs only when the semantics are stable and cross-project.

๐Ÿ› ๏ธ Versioning & Breaking Changes

The current development line tracks 1.x-dev. There is no published breaking-change history yet for this package.

โ“ FAQ

Q: Why does this package expose traits instead of one giant helper class?
Traits let enums opt into only the ergonomics they need while keeping the public surface explicit.

Q: Why is there no Contracts namespace?
Public interfaces stay in the root namespace so the package does not hide core API behind a generic bucket.

Q: Is ComparisonResult a PHP polyfill?
No. It is a Fast Forward enum for comparator-style semantics, not a promise of native compatibility.

๐Ÿ›ก License

MIT ยฉ 2026 Felipe Sayรฃo Lobato Abreu

๐Ÿค Contributing

Issues, pull requests, and documentation improvements are welcome.

  • Read AGENTS.md for repository-specific guidance
  • Run composer dump-autoload
  • Run ./vendor/bin/dev-tools tests
  • Update the README and relevant docs when changing public API

๐Ÿ”— Links