Home / News / PHP: When to Enum?

PHP: When to Enum?

Sarcastic Summary:
PHP Enum, a type that defines a set of values, is often overrated. While it may seem like a classic PHP class, it’s a special data type designed for specific scenarios, such as dynamic values or immutable lists. However, if your set of values is dynamic, trivial, or rarely updated, enums are not the best choice. Enum can lead to less defensive code, no more switch cases, and no more boilerplates.

In terms of maintaining and extending enums, existing resources can be useful, but it’s essential to follow the DDD principles and keep the enums in the domain layer when applicable. For shared enums across multiple layers, they can be placed in a shared module or in a separate module, depending on their relationship to the business. If the enum is not related to the domain, it can be placed in other layers.

While enums may provide some benefits, such as type safety, they can also lead to rigid and inflexible code. Therefore, it’s crucial to strike a balance between modularity, flexibility, and type safety. Avoid sacrificing modularity and flexibility for type safety, especially in complex scenarios where enums may become too strict.

In summary, while PHP Enum can be a useful tool for defining fixed

PHP Enum are meant to define a set of possible values.

While it may look like a classic PHP class, it’s a special data type, and the idea is to enforce strong type for a specific usage.

Avoid Enum when…

  • your set of values is highly dynamic (your app may allow users or third parties to add new types)
  • your set of values is trivial and will never expand
  • you are refactoring legacy codebase: it’s not meant to replace everything
  • your set of values is frequently updated: it’s more appropriate for immutable lists

In a nutshell, don’t sacrifice modularity and flexibility for the sake of type safety .

In some cases, Enum are just too rigid for the business even if you are a better person with strong types.

Less defensive code

Wile PHP Enum dot not make sense all the time, it can increase code quality, for sure.

You will definitely reduce the amount of exceptions, but also value and null checks.

For example, you don’t want that:

$status = (string) $_POST['status'];
if (!in_array($status, ['draft', 'published', 'archived'], true)) {
    throw new Exception("Invalid status!");
}

Instead, you may have this:

function save(PostStatus $status) {
    // do what you want with $status
}

No more switch

Large switch blocks are difficult to read and prone to various bugs, as static analysis will likely miss some of them, and you must manually check and handle invalid cases.

Again, it does not mean you should replace all existing switch cases with PHP Enums in your codebase, but why not introduce this data type for new features?

Boilerplates and maintenance

There are great benefits, but how will you use PHP enum?

What’s is the good practice?

Let’s say you have to define user roles.

You can write this Enum:

enum UserRole: string {
    case Admin = 'Administrator';
    case Editor = 'Editor';
}

or this Enum:

enum UserRole {
    case Admin;
    case Editor;

    public function label(): string {
        return match($this) {
            self::Admin => 'Administrator',
            self::Editor => 'Editor',
        };
    }
}

The first one is a backed Enum with string values and the second one is a pure enum with a custom method to retrieve labels.

You may choose the first right away, as it’s less code, and backed enums are particularly useful when the value is stored in DB or serialized as string.

However, the second one may be more convenient for complex logic or localization.

Although, ensure all devs use the same method name (label()) when they define new Enums.

Extending Enums

You may use existing resources on GitHub, like this one.

It should cover common needs for dev teams.

PHP Enum can implement interfaces, which can guarantee the use of standard methods like label():

interface EnumOurWay
{
    public function label(): string;
}

enum UserRole implement EnumOurWay {
    case Admin;
    case Editor;

    public function label(): string {
        return match($this) {
            self::Admin => 'Administrator',
            self::Editor => 'Editor',
        };
    }
}

DDD: domain modeling

Enum must fit your domain. Otherwise, it’s unnecessary code complexity.

That would also explain why you should keep it in the domain layer when you apply strict DDD principles (e.g., value objects).

However, what do you do with shared enums that are used across multiple layers?

You would likely place it in a shared module, like common.

Likewise, if the Enum is not related to the business (e.g., network status), then it belongs to other layers.

Wrap this up

Developers want stricter types, and this is what they get with PHP Enums.

These structures are perfect for fixed sets of possible values and remove the hassle of various checks.

Although, it’s not magic, and you should resist the temptation to introduce it everywhere.

Tagged:

Leave a Reply

Your email address will not be published. Required fields are marked *