{"id":20012302,"url":"https://github.com/archtechx/enums","last_synced_at":"2025-05-14T05:10:29.809Z","repository":{"id":42656041,"uuid":"461584280","full_name":"archtechx/enums","owner":"archtechx","description":"Helpers for making PHP enums more lovable.","archived":false,"fork":false,"pushed_at":"2024-12-27T20:09:02.000Z","size":47,"stargazers_count":523,"open_issues_count":4,"forks_count":25,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-04-11T00:02:22.178Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/archtechx.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-02-20T18:51:54.000Z","updated_at":"2025-04-07T06:39:44.000Z","dependencies_parsed_at":"2024-02-04T23:25:58.021Z","dependency_job_id":"96805b29-d5bc-4d5c-af9b-6624ac3641c1","html_url":"https://github.com/archtechx/enums","commit_stats":{"total_commits":24,"total_committers":8,"mean_commits":3.0,"dds":"0.41666666666666663","last_synced_commit":"922b6abdc1a0da0b9395cde7fe3b2cfabdbfc9c9"},"previous_names":[],"tags_count":9,"template":false,"template_full_name":"archtechx/template","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/archtechx%2Fenums","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/archtechx%2Fenums/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/archtechx%2Fenums/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/archtechx%2Fenums/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/archtechx","download_url":"https://codeload.github.com/archtechx/enums/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254076848,"owners_count":22010611,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-13T07:29:40.307Z","updated_at":"2025-05-14T05:10:29.787Z","avatar_url":"https://github.com/archtechx.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Enums\n\nA collection of enum helpers for PHP.\n\n- [`InvokableCases`](#invokablecases)\n- [`Names`](#names)\n- [`Values`](#values)\n- [`Options`](#options)\n- [`From`](#from)\n- [`Metadata`](#metadata)\n- [`Comparable`](#comparable)\n\nYou can read more about the original idea on [Twitter](https://twitter.com/archtechx/status/1495158228757270528).\n\n## Installation\n\nPHP 8.1+ is required.\n\n```sh\ncomposer require archtechx/enums\n```\n\n## Usage\n\n### InvokableCases\n\nThis helper lets you get the value of a backed enum, or the name of a pure enum, by \"invoking\" it — either statically (`MyEnum::FOO()` instead of `MyEnum::FOO`), or as an instance (`$enum()`).\n\nThat way, you can use enums as array keys:\n```php\n'statuses' =\u003e [\n    TaskStatus::INCOMPLETE() =\u003e ['some configuration'],\n    TaskStatus::COMPLETED() =\u003e ['some configuration'],\n],\n```\n\nOr access the underlying primitives for any other use cases:\n```php\npublic function updateStatus(int $status): void;\n\n$task-\u003eupdateStatus(TaskStatus::COMPLETED());\n```\n\nThe main point: this is all without [having to append](https://twitter.com/archtechx/status/1495158237137494019) `-\u003evalue` to everything.\n\nThis approach also has *decent* IDE support. You get autosuggestions while typing, and then you just append `()`:\n```php\nMyEnum::FOO; // =\u003e MyEnum instance\nMyEnum::FOO(); // =\u003e 1\n```\n\n#### Apply the trait on your enum\n```php\nuse ArchTech\\Enums\\InvokableCases;\n\nenum TaskStatus: int\n{\n    use InvokableCases;\n\n    case INCOMPLETE = 0;\n    case COMPLETED = 1;\n    case CANCELED = 2;\n}\n\nenum Role\n{\n    use InvokableCases;\n\n    case ADMINISTRATOR;\n    case SUBSCRIBER;\n    case GUEST;\n}\n```\n\n#### Use static calls to get the primitive value\n```php\nTaskStatus::INCOMPLETE(); // 0\nTaskStatus::COMPLETED(); // 1\nTaskStatus::CANCELED(); // 2\nRole::ADMINISTRATOR(); // 'ADMINISTRATOR'\nRole::SUBSCRIBER(); // 'SUBSCRIBER'\nRole::GUEST(); // 'GUEST'\n```\n\n#### Invoke instances to get the primitive value\n```php\npublic function updateStatus(TaskStatus $status, Role $role)\n{\n    $this-\u003erecord-\u003esetStatus($status(), $role());\n}\n```\n\n### Names\n\nThis helper returns a list of case *names* in the enum.\n\n#### Apply the trait on your enum\n```php\nuse ArchTech\\Enums\\Names;\n\nenum TaskStatus: int\n{\n    use Names;\n\n    case INCOMPLETE = 0;\n    case COMPLETED = 1;\n    case CANCELED = 2;\n}\n\nenum Role\n{\n    use Names;\n\n    case ADMINISTRATOR;\n    case SUBSCRIBER;\n    case GUEST;\n}\n```\n\n#### Use the `names()` method\n```php\nTaskStatus::names(); // ['INCOMPLETE', 'COMPLETED', 'CANCELED']\nRole::names(); // ['ADMINISTRATOR', 'SUBSCRIBER', 'GUEST']\n```\n\n### Values\n\nThis helper returns a list of case *values* for backed enums, or a list of case *names* for pure enums (making this functionally equivalent to [`::names()`](#names) for pure Enums)\n\n#### Apply the trait on your enum\n```php\nuse ArchTech\\Enums\\Values;\n\nenum TaskStatus: int\n{\n    use Values;\n\n    case INCOMPLETE = 0;\n    case COMPLETED = 1;\n    case CANCELED = 2;\n}\n\nenum Role\n{\n    use Values;\n\n    case ADMINISTRATOR;\n    case SUBSCRIBER;\n    case GUEST;\n}\n```\n\n#### Use the `values()` method\n```php\nTaskStatus::values(); // [0, 1, 2]\nRole::values(); // ['ADMINISTRATOR', 'SUBSCRIBER', 'GUEST']\n```\n\n### Options\n\nThis helper returns an associative array of case names and values for backed enums, or a list of names for pure enums (making this functionally equivalent to [`::names()`](#names) for pure Enums).\n\n#### Apply the trait on your enum\n```php\nuse ArchTech\\Enums\\Options;\n\nenum TaskStatus: int\n{\n    use Options;\n\n    case INCOMPLETE = 0;\n    case COMPLETED = 1;\n    case CANCELED = 2;\n}\n\nenum Role\n{\n    use Options;\n\n    case ADMINISTRATOR;\n    case SUBSCRIBER;\n    case GUEST;\n}\n```\n\n#### Use the `options()` method\n```php\nTaskStatus::options(); // ['INCOMPLETE' =\u003e 0, 'COMPLETED' =\u003e 1, 'CANCELED' =\u003e 2]\nRole::options(); // ['ADMINISTRATOR', 'SUBSCRIBER', 'GUEST']\n```\n\n#### stringOptions()\n\nThe trait also adds the `stringOptions()` method that can be used for generating convenient string representations of your enum options:\n```php\n// First argument is the callback, second argument is glue\n// returns \"INCOMPLETE =\u003e 0, COMPLETED =\u003e 1, CANCELED =\u003e 2\"\nTaskStatus::stringOptions(fn ($name, $value) =\u003e \"$name =\u003e $value\", ', ');\n```\nFor pure enums (non-backed), the name is used in place of `$value` (meaning that both `$name` and `$value` are the same).\n\nBoth arguments for this method are optional, the glue defaults to `\\n` and the callback defaults to generating HTML `\u003coption\u003e` tags:\n```php\n// \u003coption value=\"0\"\u003eIncomplete\u003c/option\u003e\n// \u003coption value=\"1\"\u003eCompleted\u003c/option\u003e\n// \u003coption value=\"2\"\u003eCanceled\u003c/option\u003e\nTaskStatus::stringOptions(); // backed enum\n\n// \u003coption value=\"ADMINISTRATOR\"\u003eAdministrator\u003c/option\u003e\n// \u003coption value=\"Subscriber\"\u003eSubscriber\u003c/option\u003e\n// \u003coption value=\"GUEST\"\u003eGuest\u003c/option\u003e\nRole::stringOptions(); // pure enum\n```\n\n### From\n\nThis helper adds `from()` and `tryFrom()` to pure enums, and adds `fromName()` and `tryFromName()` to all enums.\n\n#### Important Notes:\n* `BackedEnum` instances already implement their own `from()` and `tryFrom()` methods, which will not be overridden by this trait. Attempting to override those methods in a `BackedEnum` causes a fatal error.\n* Pure enums only have named cases and not values, so the `from()` and `tryFrom()` methods are functionally equivalent to `fromName()` and `tryFromName()`\n\n#### Apply the trait on your enum\n```php\nuse ArchTech\\Enums\\From;\n\nenum TaskStatus: int\n{\n    use From;\n\n    case INCOMPLETE = 0;\n    case COMPLETED = 1;\n    case CANCELED = 2;\n}\n\nenum Role\n{\n    use From;\n\n    case ADMINISTRATOR;\n    case SUBSCRIBER;\n    case GUEST;\n}\n```\n\n#### Use the `from()` method\n```php\nRole::from('ADMINISTRATOR'); // Role::ADMINISTRATOR\nRole::from('NOBODY'); // Error: ValueError\n```\n\n#### Use the `tryFrom()` method\n```php\nRole::tryFrom('GUEST'); // Role::GUEST\nRole::tryFrom('NEVER'); // null\n```\n\n#### Use the `fromName()` method\n```php\nTaskStatus::fromName('INCOMPLETE'); // TaskStatus::INCOMPLETE\nTaskStatus::fromName('MISSING'); // Error: ValueError\nRole::fromName('SUBSCRIBER'); // Role::SUBSCRIBER\nRole::fromName('HACKER'); // Error: ValueError\n```\n\n#### Use the `tryFromName()` method\n```php\nTaskStatus::tryFromName('COMPLETED'); // TaskStatus::COMPLETED\nTaskStatus::tryFromName('NOTHING'); // null\nRole::tryFromName('GUEST'); // Role::GUEST\nRole::tryFromName('TESTER'); // null\n```\n\n### Metadata\n\nThis trait lets you add metadata to enum cases.\n\n#### Apply the trait on your enum\n```php\nuse ArchTech\\Enums\\Metadata;\nuse ArchTech\\Enums\\Meta\\Meta;\nuse App\\Enums\\MetaProperties\\{Description, Color};\n\n#[Meta(Description::class, Color::class)]\nenum TaskStatus: int\n{\n    use Metadata;\n\n    #[Description('Incomplete Task')] #[Color('red')]\n    case INCOMPLETE = 0;\n\n    #[Description('Completed Task')] #[Color('green')]\n    case COMPLETED = 1;\n\n    #[Description('Canceled Task')] #[Color('gray')]\n    case CANCELED = 2;\n}\n```\n\nExplanation:\n- `Description` and `Color` are userland class attributes — meta properties\n- The `#[Meta]` call enables those two meta properties on the enum\n- Each case must have a defined description \u0026 color (in this example)\n\n#### Access the metadata\n\n```php\nTaskStatus::INCOMPLETE-\u003edescription(); // 'Incomplete Task'\nTaskStatus::COMPLETED-\u003ecolor(); // 'green'\n```\n\n#### Creating meta properties\n\nEach meta property (= attribute used on a case) needs to exist as a class.\n```php\n#[Attribute]\nclass Color extends MetaProperty {}\n\n#[Attribute]\nclass Description extends MetaProperty {}\n```\n\nInside the class, you can customize a few things. For instance, you may want to use a different method name than the one derived from the class name (`Description` becomes `description()` by default). To do that, override the `method()` method on the meta property:\n```php\n#[Attribute]\nclass Description extends MetaProperty\n{\n    public static function method(): string\n    {\n        return 'note';\n    }\n}\n```\n\nWith the code above, the description of a case will be accessible as `TaskStatus::INCOMPLETE-\u003enote()`.\n\nAnother thing you can customize is the passed value. For instance, to wrap a color name like `text-{$color}-500`, you'd add the following `transform()` method:\n```php\n#[Attribute]\nclass Color extends MetaProperty\n{\n    protected function transform(mixed $value): mixed\n    {\n        return \"text-{$value}-500\";\n    }\n}\n```\n\nAnd now the returned color will be correctly transformed:\n```php\nTaskStatus::COMPLETED-\u003ecolor(); // 'text-green-500'\n```\n\nYou can also add a `defaultValue()` method to specify the value a case should have if it doesn't use the meta property. That way you can apply the attribute only on some cases and still get a configurable default value on all other cases.\n\n#### Use the `fromMeta()` method\n```php\nTaskStatus::fromMeta(Color::make('green')); // TaskStatus::COMPLETED\nTaskStatus::fromMeta(Color::make('blue')); // Error: ValueError\n```\n\n#### Use the `tryFromMeta()` method\n```php\nTaskStatus::tryFromMeta(Color::make('green')); // TaskStatus::COMPLETED\nTaskStatus::tryFromMeta(Color::make('blue')); // null\n```\n\n#### Recommendation: use annotations and traits\n\nIf you'd like to add better IDE support for the metadata getter methods, you can use `@method` annotations:\n\n```php\n/**\n * @method string description()\n * @method string color()\n */\n#[Meta(Description::class, Color::class)]\nenum TaskStatus: int\n{\n    use Metadata;\n\n    #[Description('Incomplete Task')] #[Color('red')]\n    case INCOMPLETE = 0;\n\n    #[Description('Completed Task')] #[Color('green')]\n    case COMPLETED = 1;\n\n    #[Description('Canceled Task')] #[Color('gray')]\n    case CANCELED = 2;\n}\n```\n\nAnd if you're using the same meta property in multiple enums, you can create a dedicated trait that includes this `@method` annotation.\n\n### Comparable\n\nThis trait lets you compare enums using `is()`, `isNot()`, `in()` and `notIn()`.\n\n#### Apply the trait on your enum\n```php\nuse ArchTech\\Enums\\Comparable;\n\nenum TaskStatus: int\n{\n    use Comparable;\n\n    case INCOMPLETE = 0;\n    case COMPLETED = 1;\n    case CANCELED = 2;\n}\n\nenum Role\n{\n    use Comparable;\n\n    case ADMINISTRATOR;\n    case SUBSCRIBER;\n    case GUEST;\n}\n```\n\n#### Use the `is()` method\n```php\nTaskStatus::INCOMPLETE-\u003eis(TaskStatus::INCOMPLETE); // true\nTaskStatus::INCOMPLETE-\u003eis(TaskStatus::COMPLETED); // false\nRole::ADMINISTRATOR-\u003eis(Role::ADMINISTRATOR); // true\nRole::ADMINISTRATOR-\u003eis(Role::NOBODY); // false\n```\n\n#### Use the `isNot()` method\n```php\nTaskStatus::INCOMPLETE-\u003eisNot(TaskStatus::INCOMPLETE); // false\nTaskStatus::INCOMPLETE-\u003eisNot(TaskStatus::COMPLETED); // true\nRole::ADMINISTRATOR-\u003eisNot(Role::ADMINISTRATOR); // false\nRole::ADMINISTRATOR-\u003eisNot(Role::NOBODY); // true\n```\n\n#### Use the `in()` method\n```php\nTaskStatus::INCOMPLETE-\u003ein([TaskStatus::INCOMPLETE, TaskStatus::COMPLETED]); // true\nTaskStatus::INCOMPLETE-\u003ein([TaskStatus::COMPLETED, TaskStatus::CANCELED]); // false\nRole::ADMINISTRATOR-\u003ein([Role::ADMINISTRATOR, Role::GUEST]); // true\nRole::ADMINISTRATOR-\u003ein([Role::SUBSCRIBER, Role::GUEST]); // false\n```\n\n#### Use the `notIn()` method\n```php\nTaskStatus::INCOMPLETE-\u003enotIn([TaskStatus::INCOMPLETE, TaskStatus::COMPLETED]); // false\nTaskStatus::INCOMPLETE-\u003enotIn([TaskStatus::COMPLETED, TaskStatus::CANCELED]); // true\nRole::ADMINISTRATOR-\u003enotIn([Role::ADMINISTRATOR, Role::GUEST]); // false\nRole::ADMINISTRATOR-\u003enotIn([Role::SUBSCRIBER, Role::GUEST]); // true\n```\n\n## PHPStan\n\nTo assist PHPStan when using invokable cases, you can include the PHPStan extensions into your own `phpstan.neon` file:\n\n```yaml\nincludes:\n  - ./vendor/archtechx/enums/extension.neon\n```\n\n## Development\n\nRun all checks locally:\n\n```sh\n./check\n```\n\nCode style will be automatically fixed by php-cs-fixer.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Farchtechx%2Fenums","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Farchtechx%2Fenums","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Farchtechx%2Fenums/lists"}