PHPackages                             leocello/sweet-enum - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. leocello/sweet-enum

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

leocello/sweet-enum
===================

Provides the ability to declare "properties" to enums using PHP Attributes, also to define classes for specific case functionalities and much more.

v0.5.0(3mo ago)66.1k↑276.2%MITPHPPHP ^8.1.0

Since Jul 3Pushed 3mo ago1 watchersCompare

[ Source](https://github.com/leocello/sweet-enum)[ Packagist](https://packagist.org/packages/leocello/sweet-enum)[ RSS](/packages/leocello-sweet-enum/feed)WikiDiscussions main Synced 2d ago

READMEChangelog (5)Dependencies (4)Versions (7)Used By (0)

SweetEnum
=========

[](#sweetenum)

**SweetEnum** is a package that will make your backed enums sweet. It allows you to add custom properties using PHP Attributes and functionality to backed enums in a very sweet way.

Also it comes with a range of methods to work with enums as collections, and allows you to define classes for specific case functionalities.

---

Installation
------------

[](#installation)

To install **SweetEnum** to your PHP project, just run:

```
composer require leocello/sweet-enum
```

---

Usage
-----

[](#usage)

### SweetEnum basic structure

[](#sweetenum-basic-structure)

`SweetEnum` will allow you by using `PHP Attributes` to define into your enums custom properties and functionality for each case without the necessity to manually iterate or `match()` all of them, what makes your enums look very sweet.

Also, it provides some cool methods to allow you to iterate among the cases as if it was a collection to help your whole application's code readability.

To make it happen, it requires the enum to implement the interface `SweetEnumContract` and use the trait `SweetEnum`. Also, for each case, you need to add the attribute `SweetCase` with its properties. This is how a simple `SweetEnum` with a custom property looks like:

```
use Leocello\SweetEnum\SweetCase;
use Leocello\SweetEnum\SweetEnum;
use Leocello\SweetEnum\SweetEnumContract;

enum Status: string implements SweetEnumContract
{
    use SweetEnum;

    #[SweetCase(
        title: 'Active',
        color: 'green',
    )]
    case Active = 'active';

    #[SweetCase(
        title: 'Inactive',
        color: 'red',
    )]
    case Inactive = 'inactive';
}
```

This already allows you to use the cool stuff `SweetEnum` provides. Note that all cases have a named argument `title` and a custom argument named `color`. Also, you can pass another argument `isOn` that will determine if that options is currently active (what is very useful to maintain functionality for legacy data) and a case class, what will be explained further in this document.

To access any property, including the custom ones, you just use them as a method to your enum case. For example:

```
echo Status::Active->title(); // Will print: Active
echo Status::Inactive->color(); // Will print: red
```

If a property doesn't exist with that name then `null` will be returned by default. Optionally you can pass a default value to the method, that argument can be named as `default` or just be the first argument passed to method. Or if you want to force only existing properties and throw an exception in case it doesn't exist, you can pass a named argument called `strict` as `true`, so an exception will be thrown in case you call an invalid attribute. For example:

```
Status::Active->hi(); // Will return `null`;
Status::Active->hi('Hello'); // Will return `"Hello"`;
Status::Active->hi(default: 'Hello!'); // Will return `"Hello!"`;
Status::Active->hi(strict: true); // Will throw an exception
```

### Default case

[](#default-case)

A constant named `DEFAULT` may be defined with the value of one of the cases of the enum. If no default case is defined, then the first case of the enum will be considered default.

Example:

```
public const DEFAULT = self::Active;
```

### Some case methods

[](#some-case-methods)

#### `->isA(class-string $type): bool`:

[](#-isaclass-stringsweetenumcontract-type-bool)

It returns if the case is of enum type given. The parameter is a `string-class` so it is pretty exception safe if a string is passed.

Example:

```
$status = Status::Active;

...

if ($status->isA(Status::class)) {
    // Do something
}

if ($status->isA(Color::class)) {
    // Not gonna happen
}
```

#### `->is(SweetEnumContract|SweetEnumContract[] $case): bool`:

[](#-issweetenumcontractsweetenumcontract-case-bool)

It accepts one argument that can be one enum case or an array of enum cases. And it returns a `bool` value being `true` if the case is the same (or one of them) passed and `false` if not.

If the case passed is not of the same enum, then an exception (`\InvalidArgumentException`) will be thrown.

Example:

```
$status = Status::Active;

...

if ($status->is(Status::Inactive)) {
    // Not gonna happen
}

if ($status->is(Color::White)) {
    // Also not gonna happen as it already threw an exception :(
}

if ($status->is(Status::Active)) {
    // Do something
}
```

#### `->toArray(SweetFields|array $fields = SweetFields::Basic): array`:

[](#-toarraysweetfieldsarray-fields--sweetfieldsbasic-array)

This method returns the properties of the case as an associative array. It receives one argument that determines the return. It can receive one of the defined fields format or a custom array of strings where each position is a field to be returned in the array.

The possible defined formats are described in the enum `SweetFields`, and they are:

- `SweetFields::Original` to return only the backed enums properties `value` and `name`
- `SweetFields::Basic` to return only the basic properties `id` and `title`
- `SweetFields::BasicWithStatus` to return only the basic properties `id` and `title` with the addition of `isOn`
- `SweetFields::Sweet` to return the properties `id`, `title` and all the custom defined properties and computed properties.
- `SweetFields::Full` to return all values for that case: `value`, `id`, `name`, `title`, `isOn` and all the custom defined properties, computed properties.

Optionally you can pass an array with all the property names desired, for example: `['title', 'color']`.

Some examples:

```
Status::Active->toArray(SweetFields::Full);
// Will return:
// [
//     'isOn' => true,
//     'value' => 'active',
//     'id' => 'active',
//     'name' => 'Active',
//     'title' => 'Active',
//     'color' => 'green',
// ]

Status::Active->toArray(['id', 'color']);
// Will return:
// [
//     'id' => 'active',
//     'color' => 'green',
// ]
```

### Static enum methods

[](#static-enum-methods)

#### `::isSameAs(string $enumClass): bool`

[](#issameasstring-enumclass-bool)

It returns if the enum class is the same as the given. The parameter is a `string-class` so it is pretty exception safe if a string is passed.

#### `::getCases(bool $onlyActive = true): array`

[](#getcasesbool-onlyactive--true-array)

This method is similar to `\BackedEnum` method `::cases()` but it uses the case status to return the options. By default only the active cases (`isOn = true`) will be returned, but if the value of argument `onlyActive` is set as `false` then all cases are returned.

#### `::getCasesInfo(SweetFields|array $fields = SweetFields::Basic, bool $onlyActive = true): array`

[](#getcasesinfosweetfieldsarray-fields--sweetfieldsbasic-bool-onlyactive--true-array)

This static method returns an array of arrays with all cases information. The information by case is the same result of the method `toArray()`, so it accepts the parameter `$fields` that behaves the same way as it does in `toArray()` where it's determined what info each case will have. Also it accepts the parameter `onlyActive` (by default = `true`), that is used to filter only active cases. For example:

```
$info = Color::getCasesInfo(SweetFields::Original);

// The variable $info will be an array where each value will be
// an associative array with the keys `value` and `name`
```

#### `::getDefaultCase(): static`

[](#getdefaultcase-static)

This method returns the default case of the enum. The default case is defined by the constant `DEFAULT`. And if it's not explicitly defined, the first case will be returned as default.

#### `::getRandomCase(bool $onlyActive = true): static`

[](#getrandomcasebool-onlyactive--true-static)

This method will return one of the cases of the enum randomly.

### Basic enum "properties"

[](#basic-enum-properties)

Because PHP doesn't support custom properties for enums, the values are accessed by methods, but we will call them properties as they will return a defined value.

#### `->id()`:

[](#-id)

This is an alias for `MyEnum::MyCase->value`.

#### `->name()`:

[](#-name)

This is an alias for `MyEnum::MyCase->name`.

#### `->title()`:

[](#-title)

This returns the string value passed to argument `title`. By default if not described it uses the enum's name (so `MyEnum::MyCase->title()` would return the same as `MyEnum::MyCase->name`).

#### `->isOn()`:

[](#-ison)

This returns the boolean value passed to argument `isOn`. By default if not described it returns `true`.

### Custom defined "properties"

[](#custom-defined-properties)

The custom properties are defined named arguments to each case. The properties then are accessed by calling a method with the same name as the key used for that value.

For example:

```
...

#[SweetCase(
    color: 'green',
)]
case Active = 'active';

...

// Accessing the value of color:
echo Status::Active->color();
```

### Computed "properties"

[](#computed-properties)

There are some cases where values need to be calculated. In those cases, you may just implement a normal method with a match among all options or apply the needed logic to return the data. But that method won't be seen by the methods `toArray()` or some collection static methods. So for that you may implement the protected method `getComputedFields()` that returns an array with all computed values for your enum cases. For example:

```
// As you can access your computed value as the other
// "property" methods, then it doesn't need to be public
protected function getRgb(): array
{
    return sscanf($this->hex(), '#%02x%02x%02x');
}

protected function getComputedFields(): array
{
    return [
        'rgb' => $this->getRgb(),
    ];
}
```

In this case the method `rgb()` can be used to access the color as RGB. Also the value of `rgb` will be available on method `toArray()` or other collection static methods.

### Case classes

[](#case-classes)

Some times your project requires some enums with a lot of logic and methods and values. With that, the readability of the code decreases. To reduce the amount of code in the enum itself, you may want to create a separate class to implement the functionality for each case separately.

To do it you may create one class for each enum case and pass it to the related case via the argument `caseClass`. Those case classes must inherit from `SweetCaseClass`. In that case all public methods implemented in those case classes can be accessed from the enum case directly.

Example:

```
// This is part of the implementation of enum Animal
...

#[SweetCase(
    caseClass: AnimalCatCaseClass::class,
    title: 'Cat',
)]
case Cat = 'cat';

// Implementation of class AnimalCatCaseClass
class AnimalCatCaseClass extends SweetCaseClass
{
    public function meow(): string
    {
        return 'Meow!';
    }
}

// Usage
echo Animal::Cat->meow(); // will print "Meow!"
```

Preferentially, you want to create a base class that implements all methods your cases need with a basic implementation. Then for each case you create a specific case where you implement only the differences. This base class inherits from `SweetCaseClass`, and each case class inherits from your base class.

In that case, you can define what is the default case class using the public constant `DEFAULT_CASE_CLASS`. And if a specific case does not have any specific implementation, then it doesn't require a specific case class and all values will already return the implementation from the base class.

For example:

```
// This is part of the implementation of enum Animal

...
public const DEFAULT_CASE_CLASS = AnimalCaseClass::class;

#[SweetCase(
    caseClass: AnimalCatCaseClass::class,
    title: 'Cat',
)]
case Cat = 'cat';

#[SweetCase(
    title: 'Sheep',
)]
case Sheep = 'sheep';
...

// Implementation of class AnimalCaseClass
class AnimalCaseClass extends SweetCaseClass
{
    public function meow(): string
    {
        return 'Sorry, a '.strtolower($this->case->title()).' cannot meow';
    }
}

// Implementation of class AnimalCatCaseClass
class AnimalCatCaseClass extends AnimalCaseClass
{
    public function meow(): string
    {
        return 'Meow!';
    }
}

// Usage
echo Animal::Cat->meow(); // will print "Meow!"
echo Animal::Sheep->meow(); // will print "Sorry, a sheep cannot meow"
```

If you want to access the values via method `->toArray()` or static method `::getCasesInfo()`, you need to add them to the computed fields. And, internally in the enum you can also access the case class methods using `$this`.

Inside the case classes, you may access the enum case associated by protected immutable property `case` (`$this->case`).

#### Method `hasClass(): bool`

[](#method-hasclass-bool)

This method returns `true` for a case if there is a case class associated to it or a default case class.

#### Method `getClassName(): ?string`

[](#method-getclassname-string)

Returns the full name of the case class associated to the enum case (or the default case class). If there is no default class and the enum case doesn't have a case class associated, `null` will be returned.

#### Method `getClassInstance(): ?SweetCaseClass`

[](#method-getclassinstance-sweetcaseclass)

Returns the instance of the case class for an enum case (or the default case class). If there is no default class and the enum case doesn't have a case class associated, `null` will be returned.

### Collection methods

[](#collection-methods)

You can use `SweetEnum` cases as a collection (that is sweet). So some methods can be used for that.

Method available:

- `foreach(\Closure $callback, bool $onlyActive = true): void`
- `map(\Closure $callback, bool $onlyActive = true): array`
- `reduce(\Closure $callback, bool $onlyActive = true): mixed`
- filter TODO
- find TODO
- sort TODO

---

Contributing
------------

[](#contributing)

Contributions are more than welcome. Please check the page: [CONTRIBUTING](CONTRIBUTING.md).

---

License
-------

[](#license)

**SweetEnum** is an open-sourced software licensed under the **[MIT license](https://opensource.org/licenses/MIT)**.

###  Health Score

42

—

FairBetter than 88% of packages

Maintenance81

Actively maintained with recent releases

Popularity26

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity44

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~126 days

Recently: every ~156 days

Total

6

Last Release

100d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/e83170ca609616ce32facc98bddf14373f94577f6d15295f176ddd3db2242ef2?d=identicon)[leocello](/maintainers/leocello)

---

Top Contributors

[![leocello](https://avatars.githubusercontent.com/u/11424365?v=4)](https://github.com/leocello "leocello (62 commits)")

###  Code Quality

TestsPest

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/leocello-sweet-enum/health.svg)

```
[![Health](https://phpackages.com/badges/leocello-sweet-enum/health.svg)](https://phpackages.com/packages/leocello-sweet-enum)
```

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
