PHP Velho Oeste 2024

The SplEnum class

(PECL spl_types >= 0.1.0)

Introduction

SplEnum gives the ability to emulate and create enumeration objects natively in PHP.

Class synopsis

SplEnum extends SplType {
/* Constants */
const NULL __default = NULL ;
/* Methods */
public getConstList ([ bool $include_default = FALSE ] ) : array
/* Inherited methods */
SplType::__construct ([ mixed $initial_value [, bool $strict ]] )
}

Predefined Constants

SplEnum::__default

Examples

Example #1 SplEnum usage example

<?php
class Month extends SplEnum {
    const 
__default self::January;
    
    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 new 
Month(Month::June) . PHP_EOL;

try {
    new 
Month(13);
} catch (
UnexpectedValueException $uve) {
    echo 
$uve->getMessage() . PHP_EOL;
}
?>

The above example will output:

6
Value not a const in enum Month

Table of Contents

add a note add a note

User Contributed Notes 8 notes

up
66
mohanrajnr at gmail dot com
8 years ago
Source: https://stackoverflow.com/a/254543/508666

if class SplEnum is not present, I would normally use something simple like the following:

abstract class DaysOfWeek
{
    const Sunday = 0;
    const Monday = 1;
    // etc.
}

$today = DaysOfWeek::Sunday;
However, other use cases may require more validation of constants and values.

abstract class BasicEnum {
    private static $constCacheArray = NULL;

private function __construct(){
      /*
        Preventing instance :)
      */
     }

    private static function getConstants() {
        if (self::$constCacheArray == NULL) {
            self::$constCacheArray = [];
        }
        $calledClass = get_called_class();
        if (!array_key_exists($calledClass, self::$constCacheArray)) {
            $reflect = new ReflectionClass($calledClass);
            self::$constCacheArray[$calledClass] = $reflect->getConstants();
        }
        return self::$constCacheArray[$calledClass];
    }

    public static function isValidName($name, $strict = false) {
        $constants = self::getConstants();

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

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

    public static function isValidValue($value) {
        $values = array_values(self::getConstants());
        return in_array($value, $values, $strict = true);
    }
}
By creating a simple enum class that extends BasicEnum, you now have the ability to use methods thusly for simple input validation:

abstract class DaysOfWeek extends BasicEnum {
    const Sunday = 0;
    const Monday = 1;
    const Tuesday = 2;
    const Wednesday = 3;
    const Thursday = 4;
    const Friday = 5;
    const Saturday = 6;
}

DaysOfWeek::isValidName('Humpday');                  // false
DaysOfWeek::isValidName('Monday');                   // true
DaysOfWeek::isValidName('monday');                   // true
DaysOfWeek::isValidName('monday', $strict = true);   // false
DaysOfWeek::isValidName(0);                          // false

DaysOfWeek::isValidValue(0);                         // true
DaysOfWeek::isValidValue(5);                         // true
DaysOfWeek::isValidValue(7);                         // false
DaysOfWeek::isValidValue('Friday');                  // false
As a side note, any time I use reflection at least once on a static/const class where the data won't change (such as in an enum), I cache the results of those reflection calls, since using fresh reflection objects each time will eventually have a noticeable performance impact (Stored in an assocciative array for multiple enums).
up
44
No Such Alias
13 years ago
Here's a clearer example usage in case anyone else finds the
current documentation confusing (as I did).

<?php
class Fruit extends SplEnum
{
 
// If no value is given during object construction this value is used
 
const __default = 1;
 
// Our enum values
 
const APPLE     = 1;
  const
ORANGE    = 2;
}

$myApple   = new Fruit();
$myOrange  = new Fruit(Fruit::ORANGE);
$fail      = 1;

function
eat(Fruit $aFruit)
{
  if (
Fruit::APPLE == $aFruit) {
    echo
"Eating an apple.\n";
  } elseif (
Fruit::ORANGE == $aFruit) {
    echo
"Eating an orange.\n";
  }
}

eat($myApple);  // Eating an apple.
eat($myOrange); // Eating an orange.

eat($fail); // PHP Catchable fatal error:  Argument 1 passed to eat() must be an instance of Fruit, integer given

?>
up
14
lsloan-php dot net at umich dot edu
9 years ago
SplEnum is a nice start for enumerated type support as an extension (making enum a part of the language would be much better), but it lacks a lot of features that enums have in other languages.  I needed functionality like the hasKey() method supported by Java.  I extended the class as SplEnumPlus and used that subclass in my code as follows:

<?php
class SplEnumPlus extends SplEnum {
    static function
hasKey($key) {
       
$foundKey = false;
       
        try {
           
$enumClassName = get_called_class();
            new
$enumClassName($key);
           
$foundKey = true;
        }
finally {
            return
$foundKey;
        }
    }
}

class
Fruit extends SplEnumPlus {
  const
APPLE     = 1;
  const
ORANGE    = 2;
}

echo (
Fruit::hasKey(Fruit::APPLE) ? 'yes' : 'no') . PHP_EOL; // yes
echo (Fruit::hasKey('banana') ? 'yes' : 'no') . PHP_EOL; // no
?>

Other useful features, like reverse value-to-key lookups, could be done in this way.  It would be helpful if this and other useful functionality were made part of SplEnum.
up
1
wrobel dot przemyslaw at gmail dot com
3 years ago
There is a quite good and mature solution here - https://github.com/myclabs/php-enum
up
1
rafageist at hotmail dot com
4 years ago
I wrote a simple solution using ... PHP! (classes and type hinting).

This package can help you, https://github.com/divengine/enum. It is a simple class, but the concept is more important!. Also you can build taxonomies of enums.

$ composer require divengine\enum;

<?php

use divengine\enum;

class
Temperature extends enum {}

class
ExtremeTemperature extends Temperature {}
class
FIRE extends ExtremeTemperature {}
class
ICE extends ExtremeTemperature {}

class
NormalTemperature extends Temperature {}
class
HOT extends NormalTemperature {}
class
COOL extends NormalTemperature {}
class
COLD extends NormalTemperature {}

function
WhatShouldIdo(Temperature $temperature) {
   ...
   if (
$temperature instanceof HOT) { ... }
   if (
$temperature == HOT::class) { ... }
   ...
}

WhatShouldIdo(new HOT());
up
1
igorsantos07 at anywhere
3 years ago
This PECL is mostly abandoned, but in case you want to use SplEnum anyway, there's a PHP 7 rewrite available for installation at https://github.com/igorsantos07/SPL_Types
up
-3
liebn0r
5 years ago
Stylistically, SplEnum kind of sucks in use. Take for example, the following:

<?php

class Animal extends SplType {
    const
MONKEY = 1;
    const
HORSE = 2;
}

function
putOnBoat( Animal $animal ) {
   
// ...
}

putOnBoat( new Animal( Animal::MONKEY) );

?>

A little redundant, right? Here's a little extra stylistic step you can take to make usage a little cleaner.

<?php

class Animal extends SplType {

    const
TYPE_MONKEY = 1;
    const
TYPE_HORSE = 2;

    static
$MONKEY;
    static
$HORSE;

}

Animal::$MONKEY = new Animal( Animal::TYPE_MONKEY );
Animal::$HORSE = new Animal( Animal::TYPE_HORSE);

function
putOnBoat( Animal $animal ) {
   
// ...
}

putOnBoat( Animal::$MONKEY );

?>
up
-7
dc at dcitservices dot com dot au
8 years ago
I use the following function getValue() to have a dynamically way to check and retrieve value without errors.

class MyEnum extends SplEnum
{
    const __default = 0;

    const C1 = 1;
    const C2 = 2;

    public function getValue($key)
    {
        $declaredElems = $this->getConstList();
        if(array_key_exists($key, $declaredElems)){
            $r = new \ReflectionClass($this);
            return $r->getConstant($key);
        }else{
            return self::__default;
        }
    }
}
To Top