Stephen R
Stephen R

Reputation: 3907

PHP: Select enum case from string value of case name

I'm looking at enum in PHP 8.1. I have a string variable gathered from a database record, and I want to select the correct enum value case based on that string. For example:

enum Test: string {
    case FOO = 'baz';
    case BAR = 'buz';
}

I can select the first of those using the string value of the case:

$x = 'baz';
$y = Test::from($x);

// $y is now `Test::FOO`.

But what about the other way around? What if $x = "FOO"? How do I select the enum case from "FOO"?

Hard-coded, it would be Test::FOO, but I don't know the syntax for using a variable. I've tried a few things like Test::{$x} but the enum syntax doesn't seem to like variables very much.

The standard example all the tutorials give seems a perfect use case for this usage, but none of them mention it.

enum Suit: string {
    case Clubs = '♣';
    case Diamonds = '♦';
    case Hearts = '♥';
    case Spades = '♠';
}

I can totally imagine needing to get from "Clubs". I can't imagine ever needing the reverse.

Upvotes: 0

Views: 1082

Answers (1)

Chris Haas
Chris Haas

Reputation: 55427

To me, storing the name of the constant and not the value defeats the purpose of a backed enum. But, reading through many of the discussions on enums, many people were against backed enums and/or stringified enums in general, so I won't argue the point except to say that I would consider it the same as storing Clubs for a class constant such as:

class Suit
{
    const Clubs = '♣';
    const Diamonds = '♦';
    const Hearts = '♥';
    const Spades = '♠'; 
}

To your question, yes you can get the enum back by using the constant function (as noted in this thread):

enum Suit: string {
    case Clubs = '♣';
    case Diamonds = '♦';
    case Hearts = '♥';
    case Spades = '♠';
}

$cardString = 'Clubs';
$cardEnumFQString = Suit::class . '::' . $cardString;
$cardEnum = constant($cardEnumFQString);

echo $cardEnum->value;

Demo here: https://3v4l.org/WTrIv#v8.1.10

Personally, when I use backed enums it is for database, URL transport or similar, and I use the value. If I want to expose anything user-facing I more often than not just add a custom attribute and I have a common utility function that parses that.

EDIT Here's some helper code that shows a trait I use to reflect on enum attributes: https://3v4l.org/QKBvU#v8.1.10. It might seem like overkill for some people, but for some objects I like to keep their meta information attached to the object instead of a separate render file.

EDIT: Enums vs Class Constants

This is not a definitive answer to the question in any way, I want to make that clear. There is definitely a lot more that I'm not covering and I'd encourage a read-through on the original discussion as well as the follow-up discussion and the over-arching ADTs RFC. There's a lot in those discussions, pros, cons, WTFs, alternatives, "I don't get it", etc.

One of the major differences between an enum and a class constant is that an enum is a first-class object in PHP and as such it can have methods, whereas a class constant is limited to scalars, scalar expressions and arrays (ignoring recent post-enum changes). This means you can pass an object that holds a specific value around, and have that object include methods. The PHP documentation has a great example for the color method on Suit.

You could define your constants in one file and include a utility class with methods like getColor(string $colorName) however there's no way to limit the choices that get passed to it, nor can you guard against someone using a literal instead of your constant.

Can you do that with pure classes? Absolutely, and many of us used libraries such as https://github.com/myclabs/php-enum or https://github.com/spatie/enum to do that. This just unifies it at the language level.

I definitely agree that it can be a grey area. I came from a .Net background originally so I've had enums for a very long time, and even wrote a "why enums vs static class members" over a decade ago, so for me I've had a long time to play with them, and was very excited when they came to PHP. The best I can tell you is that you might just have to play with them to see if they fit. I'm very certain that some long-time PHP people won't use enums ever because they've solved this problem in the past in other ways, and I think that's okay, too.

Upvotes: 2

Related Questions