All posts

Use Constants and Enums Instead of Magic Values

A string like 'admin' scattered across the codebase is a typo waiting to happen. Give important values one searchable definition.

Marijan Kopčić••2 min read
Use Constants and Enums Instead of Magic Values

A string like 'admin' scattered across a codebase looks harmless. Then someone types 'Admin' in one place, a permission check silently fails, and nobody can find every place the value is used because a search for admin returns four hundred results. Constants and enums give important values a single, searchable definition.

Magic strings

public function isAdmin(User $user): bool
{
    return $user->type === 'admin';
}

The value 'admin' is now defined wherever someone typed it. There is no list of valid user types, no autocomplete and no way for static analysis to tell you that 'amdin' is a typo.

Give the value a name

Since PHP 8.1, a backed enum is the cleanest way to model a fixed set of values:

enum UserType: string
{
    case Admin = 'admin';
    case Editor = 'editor';
    case Member = 'member';
}

public function isAdmin(User $user): bool
{
    return $user->type === UserType::Admin;
}

Eloquent can cast the column straight to the enum, so the model always holds a UserType, never a raw string:

protected function casts(): array
{
    return ['type' => UserType::class];
}

Why this pays off

One definition, findable everywhere. "Find usages" on UserType::Admin shows every place that cares about admins. A text search for 'admin' shows comments, translations and CSS classes too.

Typos become errors. UserType::Amdin fails immediately. 'amdin' fails silently, in production.

Safe renames. Changing the stored value means editing one line in the enum, not hunting through the codebase.

Self-documenting types. A method that accepts UserType $type tells you exactly which values are allowed. A method that accepts string $type tells you nothing.

Where constants are not the answer

Not every literal needs a name. 0, 1 and an empty string in obvious places are fine. And values that differ per environment, such as API keys, limits or URLs, belong in config files, not in constants. Use config('services.billing.limit'), never a hard-coded number.

A useful rule of thumb:

  • A fixed set of related values → a backed enum.
  • A single fixed value used in several places → a class constant.
  • A value that changes per environment → a config file.

The practical test

Search your code for a status or type string, such as 'pending' or 'admin', and count the files it appears in. If it is more than one, it deserves an enum. Create it, cast the column, and replace the strings one file at a time.

Keep reading