How do Enums work in PHP?

Enums are something i've shied away from in the past, either not using them to their full potential or just not using them at all. After all, a class with some constants does the job just fine right? I've finally got round to using them properly and I'd like to tell you about it!

This post is for people who are new to enums and people who don't quite fully understand them yet. They can be both simple and very powerful tools to have at your disposal.

There a few different ways to use enums and the most simple is the Pure Enum. Let's show what this looks like and then discuss what they can be used for.

How to create a pure enum

namespace App\Enums;

enum RockPaperScissorEnum
{
    case ROCK;
    case PAPER;
    case SCISSORS;
}

As you can see an enum looks pretty much like a standard class or trait and to define a value you use case ROCK; Pretty standard so far, but on first look, it might not appear to be very useful, especially when each case doesn't have a value assigned to it. The next question you might ask is how would I use this pure enum or what's the benefit?

Two main benefits are:

  • Type Hinting
  • Enum methods

Since enums are an object, this means you can use them to type hint your methods. Let's look at this example where we play a game of Rock, Paper, Scissors. We can enforce that the players moves are from the RockPaperScissorEnum class and not just some random value. Pretty nice!

enum RockPaperScissorEnum
{
    case ROCK;
    case PAPER;
    case SCISSORS;
}

class Game {
    
    public function playGame(RockPaperScissorEnum $yourMove, RockPaperScissorEnum $opponentsMove) {
        // game logic
    }
    
}

$game = new Game();
$game->playGame(RockPaperScissorEnum::PAPER, RockPaperScissorEnum::ROCK);

This is also an example of how you would use pure enums in your code. You'd use the scope resolution operator (the double colon) RockPaperScissorEnum::PAPER to access it.

One of the things that might really sell enums to you are enum methods, which when you understand how they work, should hopefully be the lightbulb moment you were needing. Enum methods allows you transform your enums into different values. More on enum methods later on in the article, so we don't get too overwhelmed. Next on the list are Backed Enums.

What are Backed Enums?

Backed enums are similar to Pure enums, however these enums are backed by a value. This is the enum that you'll probably use most when coding. Let's look at an example. We'll stick with the Rock, Paper, Scissors theme if that's ok.

namespace App\Enums;

enum RockPaperScissorEnum : string
{
    case ROCK = 'Rock';
    case PAPER = 'Paper';
    case SCISSORS = 'Scissors';
}

As you can see, its just a pure enum, but now it has values assigned to each case. Also take notice of the type we assigned to the enum declaration.

enum RockPaperScissorEnum: string {} When using backed enums, we need to declare what type the value of our enums are and in this case we're using strings. If you don't set the type, you'll get an error. Note that you can only use int or string types and you can't use multiple (union) types. : int|string will also throw an error.

Your next question might be, how do I use a backed enum? There are a few ways,

  • You can access a single enum and grab its value
  • You can grab all the enums into one object and loop over them. Great for use in foreach loops.

How to get the value of a backed enum

To get the value of a single enum, you can use a read-only property called ->value. Example below:

RockPaperScissorEnum::ROCK->value; // Rock
RockPaperScissorEnum::PAPER->value; // Paper

You can also do this in your PHP / laravel blade files just as easily too. Make sure you reference the full namespace.

<h1 class="display-3 text-center text-md-start pt-4">
    {{ App\Enums\RockPaperScissorEnum::ROCK->value }}, Paper, Scissors
</h1>

How to get all the values of a backed enum

Lets say you want to populate a HTML select element with all the cases / values of your enum. This is simple to do, you can use the cases() method on your enum class. Let's show an example:

<select>
    @foreach(\App\Enums\RockPaperScissorEnum::cases() as $moves)
        <option value="{{ $moves->value }}">{{ $moves->value }}</option>
    @endforeach
</select>

The above code will give you a select box with 3 options: Rock, Paper, Scissors.

As before you can use the ->value property to get the actual value. If needed you can also use the ->name property to get the name / case of the enum. In the example above using ->name would return ROCK . Next let's move onto enum methods.

What are enum methods?

So remember when I said that enum methods might just be the lightbulb moment you needed to see the real value of enums? Well hopefully this is your lightbulb moment. Enum methods are exactly that, any type of method you can think of, which you can use to transform your enum cases. Let's dive in with an example:

namespace App\Enums;

enum RockPaperScissorEnum: string
{
    case ROCK = 'Rock';
    case PAPER = 'Paper';
    case SCISSORS = 'Scissors';

    public function outcome(): string
    {
        return match ($this) {
            self::ROCK => 'Beats Scissors',
            self::PAPER => 'Beats Rock',
            self::SCISSORS => 'Beats Paper',
        };
    }
}

In the above example I've created a public function (method) called outcome() and in this function I'm using a match statement to map the enum cases to the values I want. Note that I can use $this as a reference to the enum and I can also use self::ROCK to access the enum. This is just a shortcut, you could also use RockPaperScissorEnum::ROCK, but as you can see, self is quicker to type.

I want to know what move beats another move, so I can do this using an enum method. This is cool!

How to use enum methods

Now that we have our outcome() method, lets use it in some code.

RockPaperScissorEnum::ROCK->outcome(); // Beats Scissors
RockPaperScissorEnum::SCISSORS->outcome(); // Beats Paper

As you can see, all you have to do is chain the ->outcome() method onto the enum case of your choice and it will print out the return value. This is also very easy to do in your blade / php files too:

<h4>Outcomes</h4>
<ul>
    <li>Rock {{ App\Enums\RockPaperScissorEnum::ROCK->outcome() }}</li>
    <li>Paper {{ App\Enums\RockPaperScissorEnum::PAPER->outcome() }}</li>
    <li>Scissors {{ App\Enums\RockPaperScissorEnum::SCISSORS->outcome() }}</li>
</ul>

Pretty good yeah? We've taken our enums with a fixed value and transformed them to suit our needs.

What about if we want all our enums returned as an array? We can use a method to achieve this! Example:

namespace App\Enums;

enum RockPaperScissorEnum: string
{
    case ROCK = 'Rock';
    case PAPER = 'Paper';
    case SCISSORS = 'Scissors';

    public static function toKeyValueArray(): array
    {
        return array_column(self::cases(), 'value', 'name');
    }

    public static function toArray(): array
    {
        return array_column(self::cases(), 'value');
    }
}

I've created two methods which will return a key => value array or a simple array. The output looks as follows:

> App\Enums\RockPaperScissorEnum::toKeyValueArray();
= [
    "ROCK" => "Rock",
    "PAPER" => "Paper",
    "SCISSORS" => "Scissors",
  ]

> App\Enums\RockPaperScissorEnum::toArray();
= [
    "Rock",
    "Paper",
    "Scissors",
  ]

If we go back to our HTML select element, here's how we can use the toKeyValueArray() method:

<select>
   @foreach(\App\Enums\RockPaperScissorEnum::toKeyValueArray() as $key => $move)
        <option value="{{ $key }}">{{ $move }}</option>
    @endforeach
</select>

And there we have it. This was an introduction to enums and how they can be used in your code. If you want to learn more about enums, you should check out the official PHP docs.



More Posts