Click here to Skip to main content
15,888,313 members
Articles / Programming Languages / PHP

Enum Support in PHP

Rate me:
Please Sign up or sign in to vote.
4.80/5 (4 votes)
15 Nov 2013CPOL3 min read 30K   3   1
Here, I’ll give you my version of enum support. If you like this approach, or if you prefer any other one, it is basically a matter of taste.

As any PHP developer knows, there is no native enum support in PHP due to the fact that PHP is a dynamic language where a variable can be anything and everything. Many have tried to implement their own version of enum support, some solutions working better than others. Here, I’ll give you my version of enum support. If you like this approach, or if you prefer any other one, it is basically a matter of taste.

An Abstract Enum Template Class

The basic idea behind the enum support is an abstract enum class with the simple functionality we want the enum to have. It includes type checking where you can check if a variable is of a certain enum type and also the possibility to verify that only allowed enum values are being used.

This is the code for the abstract class:

PHP
abstract class Enum {
    protected $value;

    /**
     * Return string representation of this enum
     *
     * @return string
     */
    public function getValue()
    {
        return $this->value;
    }

   /**
     * Tries to set the value  of this enum
     *
     * @param string $value
     * @throws Exception If value is not part of this enum
     */
    public function setValue($value)
    {
        if ($this->isValidEnumValue($value))
            $this->value = $value;
        else
            throw new Exception("Invalid type specified!");
    }

   /**
     * Validates if the type given is part of this enum class
     *
     * @param string $checkValue
     * @return bool
     */
    public function isValidEnumValue($checkValue)
    {
        $reflector = new ReflectionClass(get_class($this));
        foreach ($reflector->getConstants() as $validValue)
        {
            if ($validValue == $checkValue) return true;
        }
        return false;
    }

    /**
     * @param string $value Value for this display type
     */
    function __construct($value)
    {
        $this->setValue($value);
    }

    /**
     * With a magic getter you can get the value from this enum using
     * any variable name as in:
     *
     * <code>
     *   $myEnum = new MyEnum(MyEnum::start);
     *   echo $myEnum->v;
     * </code>
     *
     * @param string $property
     * @return string
     */
    function __get($property)
    {
        return $this->value;
    }

    /**
     * With a magic setter you can set the enum value using any variable
     * name as in:
     *
     * <code>
     *   $myEnum = new MyEnum(MyEnum::Start);
     *   $myEnum->v = MyEnum::End;
     * </code>
     *
     * @param string $property
     * @param string $value
     * @throws Exception Throws exception if an invalid type is used
     */
    function __set($property, $value)
    {
        $this->setValue($value);
    }

    /**
     * If the enum is requested as a string then this function will be automatically
     * called and the value of this enum will be returned as a string.
     *
     * @return string
     */
    function __toString()
    {
        return (string)$this->value;
    }
}

How to Create Your Own Enum

To create your own enum using this abstract class, simply do in the following way:

PHP
class MyEnum extends Enum {
  const TypeA = "1";
  const TypeB = "2";
  const TypeC = "3";
}

The only thing your class should contain is constants with the values of your enum. Why the integers are written as strings is explained further down. It’s not mandatory, but it brings some extra possibilities.

To use the new enum in code, simply write in the following way:

PHP
// Create a new enum with a given value
$myType = new MyEnum(MyEnum::TypeB);

// Change value of enum
$myType->setValue(MyEnum::TypeC);

// Check value of enum
if ($myType == MyEnum::TypeC) {
  // do something
}

// Verify that variable is of enum type
if ($myType instanceof MyEnum) {
  // do something
}

// Force type checking in function definitions
function myFunction(MyEnum $myType)
{
  // do something
}

Notes on the Abstract Enum Class

The code for the abstract enum class is quite straight forward, but there are a few things I would like to highlight:

  • The magic __get and __set are not at all needed. They just add an easier way to get and set the value of the enum. Instead of, as in the code above, typing $myType->setValue(MyEnum::TypeC); you can shorten it down to just $myType->v = MyEnum::TypeC;. Your IDE might complain that you’re accessing a dynamically assigned variable, but in our abstract enum class, all dynamic variables are redirected to the protected $value variable, and you won’t get any errors when you run it.
  • When you create an instance of the enum, you simply create an object. To access the actual value of that enum object, you have to use the getValue() function. But if you use string enum values (as illustrated further up) you can use the magic __string() function to access the enum’s value right off from the object, as illustrated here:
    PHP
    $e = new MyEnum(MyEnum::Start);
    if ($e == MyEnum::TypeA) {
      // Do something
    }
    This only works if you define your enum values as strings as illustrated in the example earlier, and if you try to access the enum as a string. The reason for this is that there is no “magic” way of converting objects to ints (or other datatypes) but you can convert them to strings. If TypeA was an integer PHP would try to convert $e to integer to match, and that would fail.
  • In the isValidEnumValue() method (in the abstract class) you can’t use the __CLASS__ constant because it refers to the abstract class and not to the class extending it. Instead, we have to use get_class($this) to get the class name of the class extending the enum.

Limitations Using This Type of Enum

When you use enums in a language having it built in, you also have an “enum understanding” in each and every enum value. That’s not the case here where each value is a string (or int). You therefore have to take a little longer way to set an enum, as illustrated here:

PHP
// First way of setting to TypeA
$myType = new MyEnum(MyEnum::TypeA);

// Second way of setting to TypeA
$myType = new MyEnum(MyEnum::TypeC);
$myType->setValue(MyEnum::TypeA);

// This way doesn't work at all though
$myType = MyEnum::TypeA;

If you can live with that, you might have found a decent enum implementation in PHP.

More Reading

If you want to read some more about the different PHP techniques used in this solution, you can continue here:

And here are some links to other people’s suggestions on enum support in PHP:

This article was originally posted at http://labs.bjfocus.co.uk/2013/11/enum-support-in-php

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
CEO BJ Focus Ltd
United Kingdom United Kingdom
Johan is the CEO of BJ Focus Ltd, a UK company specialised in the development of business structure platforms helping companies to structure flows of organisable data.

He writes articles on the BJ Lab's blog, especially when his customers keep asking the same thing. You might find a few of these articles here on CodeProject.

Currently his focus is on building MVC web apps on the Azure platform, but PHP and MySQL get their share of attention as well.

Johan has double masters, in business and in software development, and an MCTS in .Net Framework 4, web applications.

Comments and Discussions

 
GeneralMy vote of 5 Pin
Niel Bah15-Nov-13 5:01
Niel Bah15-Nov-13 5:01 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.