Categories
Software Development Web Development

Php Backed Enums don’t forget to call value

This is about the change from the old way of doing things to the new Enum classes.  I’m currently working to switch over from the old way to the new way, one file at a time.

This means in places where I refactor code I have to remember to call ->value. Hence the article title “Php Backed Enums don’t forget to call value”

Well thanks to my IDE PhpStorm, I caught this error before it happened to me… in most places.

I like the concept of having an Enum class as up until version PHP 8.1 you had to create class constants and pretend they were real Enums.

Old php enums

Old PHP Enums Example

Here is how we used to do PHP Enums for forever until version 8.1

class ImageDataEnum
{
    const HEIGHT = 'height';
    const SIZE_STRING = 'size';
    const IMAGE_URL = 'image_url';
    const WIDTH = 'width';
}

And to use that in any code you simply did the following where you needed a value.

$height = ImageDataEnum::HEIGHT;

And inside $height would be the string “height” you could use this to make sure a value exists without having to spell it out every time, reducing the likelihood of bugs. This is very straight forward and easy. You can still add constants to Enum classes and use them, but it feels better using case instead.

New Enums

A backed enum looks like this. Note const is now case, class is now enum, but the rest is about the same.

enum ImageDataEnum: string
{
    case HEIGHT = 'height';
    case SIZE_STRING = 'size';
    case IMAGE_URL = 'image_url';
    case WIDTH = 'width';
}

Notice the word “string” you can use int or string but not a combination of both. Backed Enums Docs here.

Now to use the new Enums like the code above you do like this

$height = ImageDataEnum::HEIGHT->value;

Otherwise $height will be an object, one that contains  handy built in methods try() and tryFrom(). See the doc links for more info on that. You can also define your own methods.

But if you fail to call ->value and you try to use this for a string comparison you will get oopsies. You can use the IDE to hunt down all cases of the old class type enums.

//this won't work
if('height' === ImageDataEnum::HEIGHT ){
 //code to do stuff in here
}

The above will result in an error telling you the comparison is not possible. You can’t compare a string to an object.

//this will work
if('height' === ImageDataEnum::HEIGHT->value ){
 //code to do stuff in here
}

You can also call ImageDataEnum::HEIGHT->name which will return HEIGHT. So you can get the name and value using those methods.

Another nice thing about the new Enum classes is they are full on classes, you can add methods to them if you want. Like checking if a value matches any of the case values or whatever your use case is.

Enums are really handy for limiting what values can be entered by users and checking against them. Another good use I have found is creating a list of options for a Database table column.

Here is an example of a column in one of my tables that stores a medias content rating type. The system later uses this in many places to make sure that the media is of this type or that the user wants to see this type of media.

enum ContentRatingsEnum: string
{
    case EVERYONE = 'everyone';
    case MATURE = 'mature';
    case RATED_X = 'rated-x';
}

This column in a media table can only contain these values and users can only select from these values as their content preference type. This is helpful because I don’t have to type those strings in 100,000 places and when I need to change one I simply refactor with my IDE features.