Enumeration in PHP


Enumeration or Enum is a common type in many programing languages and databases.  This fact alone makes it a mystery as to why PHP chose not to be included on Enumeration wagon.  Why is Enumeration so important?  My answer to that question is simple, It allows you to control your data and limit run-time errors.

So how do we can past this limitation in PHP?  In the following steps I will explain how you can implement Enums in your PHP project.  To do this you will need to understand some basic OOP theory such as how to build a class, and implement a class interface.

The first thing you need to do is create a class interface for your new Enum objects. An Interface is a contract for classes that implement the interface. What does that mean? It’s simple, any methods declared within the interface must be implemented by the implementing class.

Why do that when I can just add those methods to my class anyway? The idea is to create a group of classes that share similar behavior but can also implement custom functionality.   We are using an interface to define the rules that we want our Enum objects to share.

Explanation for beginners will be provided at the end of this post if requested.

1. Create IEnum Interface

Interface IEnum
{
    function __constructor($_value = "")

    public function Value( )
    public function Set($_value)
}

2. Create our Enum Object Implementing our Interface.

Class Shape implements IEnum
{
    private $m_value;

    function __constructor($_value = "")
    {
        if ($_value != "")
        {
            $this->Set($_value);
        }
    }	

    public function Value()
    {
        return $this->m_value;
    }

    public function Set($_value)
    {
        switch($_value)
        {
	    case "Square":
	    case "Circle":
	    case "Triangle":
	    case "Rectangle":
		$this->m_value = $_value;
		break;
	    default:
		throw new Exception("Enumeration Error, Set
                    value (" . $_value . ") is not an option for
                    this Enumeration");
	}
    }
}

3. Using our Enumerator.

Working Example Using Constructor:

$shape = new Shape("Circle");
echo $shape->Value();

Output: Circle

Working Example Using Set():

$shape = new Shape();
$shape->Set("Square");
echo $shape->Value();

Output: Square

Exception Example Using Set():

$shape = new Shape();
$shape->Set("Trapazoid");
echo $shape->Value();

Output: Enumeration Exception.

— Detailed Explanation —
This technique assumes that you understand basic OOP theory.

The concepts used in this technique include; OOP in PHP, Interface Design in PHP, Class Design in PHP,Interface Implementation in PHP, Intermediate understanding of php syntax.

This technique is accomplished by the following steps:

  1. Defining an Interface Contract.
  2. Creating a class objects that implements the Interface.
  3. Define a list of options.
  4. Defining the business rules for enumeration.

1. Defining an Interface Contract.

An interface is a contract for a class object. The terms of the contract are defined in the interface and the class must follow those terms. Our Interface will define the rules that all Enumeration objects will be held to in the contract.

For the purpose of good practice we are going to prefix our Interface with the ‘I’ prefix, allowing us to easily identify the difference between an Interface and a class. Another good practice in naming an interface is to use the name to describe the Interface. Our interface contract will define the terms for enumeration, therefore we will call it IEnum.

Interface IEnum { }

Now that we have created our contract, we now need to define the terms of the contract. Our contract will have 3 simple terms.

  • A constructor must be created
  • A function named Set() must be implemented.
  • A function named Value() must be implemented.
Interface IEnum
{
    function __constructor($_value = "")

    public function Value( )
    public function Set($_value)
}

The purpose of these terms will be more explained in the next section.

2. Creating a class objects that implements the Interface.

We are now going to create a class to define our enumeration object. We are making a Shape object that provides a list of shape values. Again using good practice we need to name our class in a way that the name describes the class.

Class Shape implements IEnum { }

The implements keyword tells us that this Shape is bound to the terms of the IEnum contract. Those terms again are:

  • A constructor must be created
  • A function named Set() must be implemented.
  • A function named Value() must be implemented.
Class Shape implements IEnum
{
    function __constructor($_value = "") { }
    public function Value() { }
    public function Set($_value) { }
}

We have now created a valid class bound to the IEnum interface contract.

3. Define a list of options.

The purpose of an Enum is to store a value selected from a tightly defined list of options. In order for us to achieve this functionality we are going to need something to store our selected value. We can tell by the terms of our contract that this value is going to be manipulated by the __constructor and the Set() functions. This means we can keep our value field private so that it can’t be messed with outside the object.

Class Shape implements IEnum
{
    private $m_value;

    function __constructor($_value = "") { }
    public function Value() { }
    public function Set($_value) { }
}

Good practice tells us to prefix our private member variables with the m_ prefix. This lets us easily know these are private and for internal use only.

Our shape enumerator is going to provide us a list of shapes to choose from. The options we want to provide are; Square, Circle, Triage and Rectangle. We will define this list inside our Set() method using a basic switch statement.

Class Shape implements IEnum
{
    private $m_value;

    function __constructor($_value = "") { }
    public function Value() { }

    public function Set($_value)
    {
        switch($_value)
        {
	    case "Square":
	    case "Circle":
	    case "Triangle":
	    case "Rectangle":
		$this->m_value = $_value;
		break;
	    default:
		throw new Exception("Enumeration Error, Set
                    value (" . $_value . ") is not an option for
                    this Enumeration");
	}
    }
}

First look at the opening block for our switch statement. ( switch($_value) ) The $_value var is being passed into the switch statement from the Set($_value) function. The value is what we will compare to our list of options.

	    case "Square":
	    case "Circle":
	    case "Triangle":
	    case "Rectangle":
		$this->m_value = $_value;
		break;

In the above section of em we are comparing our $_value to each of the case options. If any of the options match our $_value we are going to set our $m_value field to store that option. Finely, to avoid running the default: action we add a simple break keyword.

The last thing we have to do is throw an exception if the value we try to set is not an option in our list.

	    default:
		throw new Exception("Enumeration Error, Set
                    value (" . $_value . ") is not an option for
                    this Enumeration");

The default: case will run automatically if none of the other cases are matched. If that happens we know that the object was passed an invalid option, therefore we need to throw an exception in order to enforce our option list. You can set the exception message to whatever you want but using good practice we chose to keep the message simple, informative, and to the point.

4. Defining the rules for enumeration.

The basic rules of enumeration say that we need to be able to choose an option from a list of defined values and be able to retrieve that value. In the previous step we created the list of options in our Set() function. Now we need to trigger that Set() function inside our constructor. This is done so that our Enum object can choose an option when it is created.

    function __constructor($_value = "")
    {
        if ($_value != "")
        {
            $this->Set($_value);
        }
    }

This constructor should be pretty easy to follow. On creation we pass the object a value that is empty by default. If the value is not empty, meaning we passed in our own value, then the Set() function is fired passing it the same $_value. If that value matches any of our options the value is saved in our local private variable for later, otherwise an exception is thrown alerting the programmer.

The last thing we need to be able to do in our Enum is retrieve the selected value.

    public function Value()
    {
        return $this->m_value;
    }

The only line of code we need in this method is one to return the value stored in our private field.

With these three simple rules, and a contract to bind an object, we can simulate the same functionality provided in other programming languages. Later we will look at how we can tighten this up even more by using abstract classes.

— Final Code —

Interface IEnum
{
    function __constructor($_value = "")

    public function Value( )
    public function Set($_value)
}

Class Shape implements IEnum
{
    private $m_value;

    function __constructor($_value = "")
    {
        if ($_value != "")
        {
            $this->Set($_value);
        }
    }	

    public function Value()
    {
        return $this->m_value;
    }

    public function Set($_value)
    {
        switch($_value)
        {
	    case "Square":
	    case "Circle":
	    case "Triangle":
	    case "Rectangle":
		$this->m_value = $_value;
		break;
	    default:
		throw new Exception("Enumeration Error, Set
                    value (" . $_value . ") is not an option for
                    this Enumeration");
	}
    }
}

— Live, Share, Learn —

One thought on “Enumeration in PHP

  1. Hi Everyone. If you use this technique please post back your experience. How did it work in your situation? — Live Share Learn.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s