Enumerations in PHP

Habdul Hazeez Feb 08, 2022
  1. Emulate Enumeration With Abstract Classes in PHP
  2. Emulate Enumeration With Abstract Classes With Validation and More Constant Values in PHP
  3. Enumeration With PHP enum
  4. Backed PHP Enumerations
  5. Backed Enumerations With Methods in PHP
  6. List The Cases of Backed Enumerations in PHP
Enumerations in PHP

This tutorial will teach you how to work with enumerations in PHP before and after PHP 8.1.

The reason is before PHP 8.1, you could only emulate enumerations with abstract classes. But, from PHP 8.1, PHP offers native support for enumerations.

Emulate Enumeration With Abstract Classes in PHP

Before PHP 8.1, you can emulate enumerations with an abstract class. Since enumeration is about assigning names to integral constant, you can create an abstract class that holds constant values.

You can get each constant value outside the class via the Scope Resolution Protocol ::.

Our next example code has an abstract class that holds class constants. Afterward, we call one of the constants via Scope Resolution Protocol.

This approach has its limitations; we’ll discuss it in the next section.

<?php
    abstract class CalenderMonths {
        const January 	= 1;
        const February 	= 2;
        const March 	= 3;
        const April 	= 4;
        const May 		= 5;
        const June 		= 6;
        const July		= 7;
        const August 	= 8;
        const September = 9;
        const October 	= 10;
        const November 	= 11;
        const December 	= 12;
    }

    $january = CalenderMonths::January;

    echo $january;
?>

Output:

1

Emulate Enumeration With Abstract Classes With Validation and More Constant Values in PHP

This example builds on our previous example. But here, we present an improved version.

This version has validation and can hold more constant values. Also, it prevents the situation whereby when you extend the class, the first extension creates a cache, and another extension still uses the same cache.

The code block emulates enumerations with an abstract class, and it has validation that prevents invalid arguments. First, we define the abstract class.

<?php
    abstract class EmulatePHPEnum {
        private static $cache_array = NULL;

        private static function get_constants() {
            if (self::$cache_array == NULL) {
                self::$cache_array = [];
            }
            $called_class = get_called_class();
            if (!array_key_exists($called_class, self::$cache_array)) {
                $reflection_object = new ReflectionClass($called_class);
                self::$cache_array[$called_class] = $reflection_object->getConstants();
            }
            return self::$cache_array[$called_class];
        }

        public static function check_valid_name($name, $is_strict = false) {
            $constants = self::get_constants();

            if ($is_strict) {
                return array_key_exists($name, $constants);
            }

            $keys = array_map('strtolower', array_keys($constants));
            return in_array(strtolower($name), $keys);
        }

        public static function check_valid_value($value, $is_strict = true) {
            $values = array_values(self::get_constants());
            return in_array($value, $values, $is_strict);
        }
    }
?>

Then, we extend it and perform the comparisons.

abstract class CalenderMonths extends EmulatePHPEnum {
	const January 	= 1;
	const February 	= 2;
	const March 	= 3;
	const April 	= 4;
	const May 		= 5;
	const June 		= 6;
	const July		= 7;
	const August 	= 8;
	const September = 9;
	const October 	= 10;
	const November 	= 11;
	const December 	= 12;
}

echo "<b>First check: </b> ";
if (CalenderMonths::check_valid_name("Nothing")) {
	echo "True";
} else {
	echo "False";
}

echo "<br />";

echo "<b>Second check: </b>";
if (CalenderMonths::check_valid_name("September")) {
	echo "True";
} else {
	echo "False";
}

echo "<br />";

echo "<b>Third check: </b>";
if (CalenderMonths::check_valid_name("september")) {
	echo "True";
} else {
	echo "False";
}

echo "<br />";

echo "<b>Fourth check: </b>";
if (CalenderMonths::check_valid_name("september", $is_strict = true)) {
	echo "True";
} else {
	echo "False";
}

echo "<br />";

echo "<b>Fifth check: </b>";
if (CalenderMonths::check_valid_name(23)) {
	echo "True";
} else {
	echo "False";
}

echo "<br />";

Output:

<b>First check</b>: False
<b>Second check</b>: True
<b>Third check</b>: True
<b>Fourth check</b>: False
<b>Fifth check</b>: False

Enumeration With PHP enum

The definition of enumerations in PHP is with the enum keyword followed by the enumeration name and a set of curly braces. Within these braces, you define cases.

We present an example in the next code block. Also, we perform some comparison checks between the cases.

Note that you can not compare enumerations with less-than or greater-than operators.

<?php
    enum ProgrammingLanguages {
        case JavaScript;
        case PHP;
        case Ruby;
        case Erlang;
        case Elixir;
    }

    $javascript = ProgrammingLanguages::JavaScript;
    $js 		= ProgrammingLanguages::JavaScript;
    $erlang     = ProgrammingLanguages::Erlang;

    echo $javascript === $js;

    echo "<br/>";

    if ($javascript === $erlang) {
        echo "True";
    } else {
        echo "False";
    }

    echo "<br/>";

    if ($javascript instanceof ProgrammingLanguages) {
        echo "True";
    } else {
        echo "False";
    }

    echo "<br />";
    if ($javascript > $js || $javascript < $js) {
        echo "True";
    } else {
        echo "False";
    }
?>

Output:

1 <br />
False <br />
True <br />
False <br />

Backed PHP Enumerations

A backed enum is an enum declaration followed by a data type for each case in the enumeration.

Before we look at a code example, kindly note the following about backed enums in PHP.

  1. When defining a value for a backed value, ensure all values have a backed value.
  2. You should declare the type of the backed value after the enumeration name.
  3. Backed values in an enum are read-only.
  4. If your enums contain scalar values, they should be unique.
  5. Backed values should be literal expressions or literals.
  6. You can access a backed value with the syntax enum_name::backed_value. Where enum_name is the enumeration name, the backed_value is the value you want to access.
  7. Backed enumerations have an internal interface called BackedEnum. This interface has two methods, from and tryFrom.
  8. The from method will throw an exception for a non-existence value. While tryFrom returns null.

The following code shows how to work with backed enumerations in PHP.

<?php
    enum Age : int {
        case John 		= 23;
        case Martinez 	= 30;
        case Mary 		= 43;
        case Velasquez 	= 25;
    }

    $first_age = Age::tryFrom(23);

    if ($first_age) {
        echo "True";
    } else {
        echo "False";
    }

    echo "<br />";

    $second_age = Age::tryFrom(98);

    if ($second_age) {
        echo "True";
    } else {
        echo "False";
    }

    echo "<br />";

    $third_age = Age::from(42);
?>

Output:

True
False

<b>Fatal error</b>: Uncaught ValueError: 42 is not a valid backing value for enum "Age"

Backed Enumerations With Methods in PHP

Backed enumerations can have methods. As a result, they can implement an interface.

You’ll find an example in the next example code.

<?php

    interface isTravel {
        public function calculate_travel_cost (int $distance_covered): int;
        public function isRequireFuel(): bool;
    }

    enum CarTypes: int implements isTravel {
        case Bughatti 		= 300;
        case Lamborghini 	= 500;
        case Ferrari 		= 450;
        case Audi 			= 350;

        public function calculate_travel_cost(int $distance_covered): int {
            return $this->value * $distance_covered;
        }

        public function isRequireFuel(): bool {
            return match($this) {
                CarTypes::Bughatti, CarTypes::Lamborghini, CarTypes::Ferrari => true,
            };
        }
    }

    $car = CarTypes::Bughatti;

    $does_it_require_fuel = $car->isRequireFuel();

    if ($does_it_require_fuel) {
        echo "True";
    } else {
        echo "False";
    }

    echo "<br />";

    $car_travel_cost = $car ->calculate_travel_cost(250);

    echo $car_travel_cost;
?>

Output:

True
75000

List The Cases of Backed Enumerations in PHP

If you’d rather list the cases of a backed enum, you can do so via the internal interface called UnitEnum. This interface has a static method defined as UnitEnum::cases.

With this interface, you can retrieve the cases in your enumerations. You’ll find an example code below.

<?php
    interface isTravel {
        public function calculate_travel_cost (int $distance_covered): int;
        public function isRequireFuel(): bool;
    }

    enum CarTypes: int implements isTravel {
        case Bughatti 		= 300;
        case Lamborghini 	= 500;
        case Ferrari 		= 450;
        case Audi 			= 350;

        public function calculate_travel_cost(int $distance_covered): int {
            return $this->value * $distance_covered;
        }

        public function isRequireFuel(): bool {
            return match($this) {
                CarTypes::Bughatti, CarTypes::Lamborghini, CarTypes::Ferrari => true,
            };
        }
    }

    $car_names = CarTypes::cases();
    echo "<pre>";
    var_dump($car_names);
    echo "</pre>";
?>

Output:

<pre>
array(4) {
  [0]=>
  enum(CarTypes::Bughatti)
  [1]=>
  enum(CarTypes::Lamborghini)
  [2]=>
  enum(CarTypes::Ferrari)
  [3]=>
  enum(CarTypes::Audi)
}
</pre>
Habdul Hazeez avatar Habdul Hazeez avatar

Habdul Hazeez is a technical writer with amazing research skills. He can connect the dots, and make sense of data that are scattered across different media.

LinkedIn