DevConf 2015

The SplEnum class

(No version information available, might only be in SVN)

Wstęp

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

Krótki opis klasy

SplEnum extends SplType {
/* Constants */
const NULL __default = null ;
/* Metody */
public array getConstList ([ bool $include_default = false ] )
/* Metody dziedziczone */
SplType::__construct ([ mixed $initial_value [, bool $strict ]] )
}

Stałe predefiniowane

SplEnum::__default

Przykłady

Przykład #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;
}
?>

Powyższy przykład wyświetli:

6
Value not a const in enum Month

Spis treści

add a note add a note

User Contributed Notes 3 notes

up
17
No Such Alias
4 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
5
mohanrajnr at gmail dot com
18 days ago
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
6
lsloan-php dot net at umich dot edu
5 months 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.
To Top