DEV Community

loading...

My opinion on the PHP 8.1 Enum RFC

rvxlab profile image RVxLab ・2 min read

TL;DR

The basic and backed enums of this RFC are a nice implementation of enums in PHP, but in its current form it simply does too much.

Foreword

Yesterday Brendt from Spatie posted a blog post about new things in PHP 8.1. The one things that caught my eye was enums and since I've been wanting them in PHP for quite a while now I got a bit excited to say the least.

Reading the RFC started good and well but the further I went, the more I disliked it.

Basic enums

The basic enum implementation of this RFC looks like so:

enum Suit {
  case Hearts;
  case Diamonds;
  case Clubs;
  case Spades;
}
Enter fullscreen mode Exit fullscreen mode

Using case to denote an enum value is slightly odd, but I'll take it. If it would be possible I believe it'd be better to omit this all together:

enum Suit {
  Hearts;
  Diamonds;
  Clubs;
  Spades;
}
Enter fullscreen mode Exit fullscreen mode

Backed enums

Backed enums very much remind me of enums in TypeScript which are incredibly useful. Having this in PHP is very nice indeed.

enum Suit: string {
  case Hearts = 'H';
  case Diamonds = 'D';
  case Clubs = 'C';
  case Spades = 'S';
}
Enter fullscreen mode Exit fullscreen mode

This feature alone would likely cause me to drop myclabs/php-enum as my enum implementation.

No mixing

Backed enums and Basic (or Pure) enums cannot be mixed together, so something like this is not allowed:

enum Suit: string {
  case Hearts = 'H';
  case Diamonds = 'D';
  case Clubs;
  case Spades;
}
Enter fullscreen mode Exit fullscreen mode

I completely agree, otherwise it would just turn into a giant mess.

Enum methods

This is the point where the RFC lost me. I understand that having methods in an enum. Hell, in some cases I add a random() method in enum classes made with myclabs/php-enum. But that's usually as far as I'm willing to go.

If you need to add an interface or trait to an enum, why not just use a class instead?

The examples list extra information you can list with an enum, but doesn't that just beat the whole point of making enums to begin with?

Closing thoughts

I'd be incredibly happy if this RFC got accepted, enums are something that PHP can really use. Unfortunately, this implementation just does too much and it wouldn't surprise me if it got rejected on that basis.

However, should it be accepted, I'll be unlikely to use those enum methods.


Thanks for reading. This was my first proper post on this site and I'd like to improve my writing skills.

Any feedback on this post is greatly appreciated.

Discussion (4)

pic
Editor guide
Collapse
nicolus profile image
Nicolas Bailly • Edited

Yeah I agree with you. I had not read the whole RFC, just the first few points and thought it was great (kinda like class constants on steroids). After reading your post I went back to the RFC and read the whole thing... And either this tries to cover some very limited use cases, or I don't understand the point of Enums.

Collapse
rvxlab profile image
RVxLab Author

Enums are particularly useful when you need to enforce a subset of items that are valid.

Let’s say you have a button that can have 4 different colours. You could make those colours an enum. Or it can have 1 of 3 sizes, that could be an enum.

Or as in the RFC, a suit can be an enum.

Now you can also solve this by just using a string, but what do you do when someone puts in an invalid value? You’d need to check for that. If you use an enum that check already happens during typechecking.

Collapse
nicolus profile image
Nicolas Bailly • Edited

Yes I think get that part, that's what I called 'class constants on steroids'. What I would do in PHP 7 is something like :

class Card
{
    const DIAMONDS = 'diamonds';
    const HEARTS   = 'hearts';
    const SPADES   = 'spades';
    const CLUBS    = 'clubs';

    const SUITS = [
        self::DIAMONDS,
        self::HEARTS,
        self::SPADES,
        self::CLUBS,
    ];


    public function __construct($suit)
    {
        if (!in_array($suit, self::SUITS)) {
            throw new InvalidArgumentException('invalid suit');
        }
    }
}

//works
$card = new Card(Card::SPADES);

//works :
$card = new Card('spades');

//throws an exception :
$card = new Card('hammers');
Enter fullscreen mode Exit fullscreen mode

With Enums it becomes a lot easier as you said.

But I don't need to put methods on my enums for that ! If I want a method that returns the shape or color of a suit I'll just create a Suit interface with a abstracts shape() and color() method and implement that method in a Spade class.
In the RFC they have an example where the color method uses a match statement to return the color and always return 'rectangle' as a shape. To me this kind of defeats the purpose of OOP.