Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

dmhall0's avatar

enum vs table vs hardcode?

As I continue building out my application I am running into more fields where the options are limited. Some are simple 2 options (e.g. yes/no), while others are more (e.g. draft/review/published/edited/rejected). Given the updates to PHP's handling of enums, I wanted to resurface this one to get an idea of what the best practices are out there? Use enums for these types of fields? Use separate tables to lookup the "name" while storing the id everywhere else? Simply hardcode the option directly into the resulted field?

What are the best practices out there, or does it depend on the situation?

Happy debating! Thanks

0 likes
6 replies
MohamedTammam's avatar

I'm not saying it's BEST PRACTICE, it's just my opinion.

If the fields are dynamic like categories for example, then database for sure.

If they are static and will never (likely never) change, then enum is a good option.

Imagine that scenario.

We have a select input with two options Published and Drafted, Then some other developer writes it at PUBLISHED and DRAFTED. That might break things in the code and will interduce typos very often.

If we use enum, it will be BlogStatus::PUBPLUSHED and BlogStatus::DRAFTED and with text editors it will be easier to know the available options and they will always be the same values.

1 like
dmhall0's avatar

@MohamedTammam Thanks for the opinion. I need to spend some time really thinking about which fields I see changing or growing in the future to determine if enum or table makes the most sense. Otherwise, what you are saying is to NEVER hard code a field like this?

MohamedTammam's avatar

@dmhall0 Hard coding a value that will have a logic depends on it, will cause typo errors and every time you want to type that value without mistakes, you will need to go and copy it from other place. with enums you can put all options in one place.

Also consider constant properties for classes.

1 like
rodrigo.pedra's avatar

I use this rule of thumb:

  • If it is an "enumerable" set of data (finite set, you can list them all, not likely to change, it can change, but not likely), AND it interferes in the application logic/workflow (such as your draft/published/... state), then I would choose an Enum
  • Otherwise, either lookup table, config file, external JSON file, etc. that is easier to change/build on the-fly

You can easily use a fancy string for an Enum value. PHP Enums accept traits, I have this trait (suppressed some other methods for brevity)

<?php

namespace App\Enums;

trait EnumUtils
{
    public function __invoke(): int|string
    {
        return $this->value;
    }

    // Allows to call Enum::VALUE() , instead of Enum::VALUE->value
    public static function __callStatic($name, $arguments)
    {
        /** @var static $case */
        foreach (static::cases() as $case) {
            if ($case->name === $name) {
                return $case->value;
            }
        }

        return new \RuntimeException('Invalid case ' . $name . ' for enum ' . static::class);
    }

    // easy comparision $enum->is(Enum::VALUE_A, Enum::VALUE_B)
    public function is(self ...$others): bool
    {
        return in_array($this, $others, true);
    }

    public function isNot(self ...$others): bool
    {
        return ! $this->is(...$others);
    }

    public static function getRandomValue(): int|string
    {
        $cases = static::cases();

        return $cases[\array_rand($cases)]->value;
    }

    public function label(): string
    {
        if (! $this instanceof LocalizedEnum) {
            return \strval($this->name);
        }

        $key = 'enums.' . $this::class . '.' . $this->value;

        if (\trans()->has($key)) {
            return \trans($key);
        }

        return \strval($this->name);
    }

    /**
     * Get the enum as an array formatted for a select.
     *
     * @return array<int|string, string>
     */
    public static function toSelectArray(): array
    {
        $cases = static::cases();
        $selectArray = [];

        /** @var self $case */
        foreach ($cases as $case) {
            $selectArray[$case->value] = $case->label();
        }

        return $selectArray;
    }
}

See the label() method. LocalizedEnum is just an empty interface I add to the Enums I want to give translation labels (Enums can also implement interfaces)

So in my ./lang/en/enums.php file I have something like this:

<?php

use App\Enums\Role;
use App\Enums\Timespan;

return [
    Timespan::class => [
        Timespan::DAYS() => 'Days',
        Timespan::HOURS() => 'Hours',
    ],

    Role::class => [
        Role::SYSTEM() => 'System Admin',
        Role::ADMIN() => 'Administrator',
        Role::STAFF() => 'Staff',
        Role::REPORTING() => 'Reporting user',
        Role::USER() => 'Regular user',
    ],
    
    // ... other enums
];

Than you can call Enum::VALUE->label() for pretty labels, and as a bonus, easy translation (if needed).

5 likes
Tray2's avatar

Is the data stored in the database, use the database even if it's just a couple of different values.

If you have several of these kinds of table, you can just add one column to it with the name of the item using it.

An example.

Let's say that we have four types of items, and they all have a genre, then instead of having four genre tables, you add a type column to the genres table.

  • id
  • type
  • name

So it would look something like this

1, 'book', 'Fantasy'
2, 'game', 'FPS'
3, 'movie', 'Horror'
4, 'book', 'Thriller'
5, 'movie', 'Thriller'
1 like
dmhall0's avatar

It's looking like enums will be the best direction for a lot of my fields where the options are limited and are highly unlikely to change. THANK YOU for all the insight.

2 likes

Please or to participate in this conversation.