tags:

views:

209

answers:

5

How can Enum-like functionality (as provided in Java and other high level languages) be used in PHP? I know PHP doesn't allow you to create enums currently, but what's the closest one could get?

A: 

As an array.

$arr = array('A','B','C','D');

$find = 'A';
$key = array_search($find,$arr);
echo $arr[$key];
David
+4  A: 

Using const, perhaps.

class SomeClass {
    const FIRSTVAL = 1;
    const SECONDVAL = 2;
};
Michael Krelin - hacker
The prob is that the `Enum` would need to be global.. class constants won't really be
Click Upvote
Well, SomeClass::FIRSTVAL can be referenced from anywhere ;-)
Michael Krelin - hacker
+1  A: 

You could use constants

class myClass {
    const aValue = 123;
    const aString = "ABC";
};

But it wouldn't give a nice way of iterating through them so i would probably opt for an associate array as it would be easier to manage:

class myClass{
  $enum = array ("first" => 123, 
                "second" => "ABC");

}
Andi
A: 

A cheap trick is to create an array with possible values. However, unlike the above answers, I'd opt for an array where key/value pairs are equal, i.e.:

<?php
$enum = Array(
'apple' => 'apple',
'pear' => 'pear',
'orange' => 'orange'
);
?>

That way, if ($enum[$value] != $value), you know the value given is not in the set.

Ofcourse, if you want the key/value pairs to be different, a regular array would be the way to go.

Duroth
+1  A: 

I use class constants, and a bit of reflection trickery.

<?php
/**
 * @package Red.Core
 * @author [email protected]
 *
 * Implements the abstract base for all enum types
 *
 * example of a typical enum:
 *
 *    class DayOfWeek extends Enum
 *    {
 *        const Sunday    = 0;
 *        const Monday    = 1;
 *        const Tuesday   = 2;
 *        const Wednesday = 3;
 *        const Thursday  = 4;
 *        const Friday    = 5;
 *        const Saturday  = 6;
 *    }
 *
 * usage examples:
 *
 *     $monday = Enum::FromString( 'DayOfWeek::Monday' );           // (int) 1
 *     $monday = DayOfWeek::Monday                                  // (int) 1
 *     $monday = Enum::ToString( 'DayOfWeek', DayOfWeek::Monday );  // (string) "DayOfWeek::Monday"
 *     $monday = Enum::Label( 'DayOfWeek', DayOfWeek::Monday );     // (string) "Monday"
 *
 **/
abstract class Enum
{
    // make sure there are never any instances created
    final private function __construct()
    {
        throw new Exception( 'Enum and Subclasses cannot be instantiated.' );
    }

    /**
     * Give the integer associated with the const of the given string in the format of "class:const"
     *
     * @param string $string
     * @return integer
     */
    final public static function FromString( $string )
    {
        if ( strpos( $string, '::' ) < 1 )
        {
            throw new Exception( 'Enum::FromString( $string ) Input string is not in the expected format.' );
        }
        list( $class, $const ) = explode( '::', $string );

        if ( class_exists( $class, false ) )
        {
            $reflector = new ReflectionClass( $class );
            if ( $reflector->IsSubClassOf( 'Enum' ) )
            {
                if ( $reflector->hasConstant( $const ) )
                {
                    return eval( sprintf( 'return %s;', $string ) );
                }
            }
        }
        throw new Excption( sprintf( '%s does not map to an Enum field', $string ) );
    }

    final public static function IsValidValue( $enumType, $enumValue )
    {
        if ( class_exists( $enumType ) )
        {
            $reflector = new ReflectionClass( $enumType );
            if ( $reflector->IsSubClassOf( 'Enum' ) )
            {
                foreach( $reflector->getConstants() as $label => $value )
                {
                    if ( $value == $enumValue )
                    {
                        return true;
                    }
                }
            }
        }
        return false;
    }

    final public static function IsValidLabel( $enumType, $enumValue )
    {
        if ( class_exists( $enumType ) )
        {
            $reflector = new ReflectionClass( $enumType );
            if ( $reflector->IsSubClassOf( 'Enum' ) )
            {
                foreach( $reflector->getConstants() as $label => $value )
                {
                    if ( $label == $enumValue )
                    {
                        return true;
                    }
                }
            }
        }
        return false;
    }

    /**
     * For a given $enumType, give the complete string representation for the given $enumValue (class::const)
     *
     * @param string $enumType
     * @param integer $enumValue
     * @return string
     */
    final public static function ToString( $enumType, $enumValue )
    {
        $result = 'NotAnEnum::IllegalValue';

        if ( class_exists( $enumType, false ) )
        {
            $reflector = new ReflectionClass( $enumType );
            $result = $reflector->getName() . '::IllegalValue';
            foreach( $reflector->getConstants() as $key => $val )
            {
                if ( $val == $enumValue )
                {
                    $result = str_replace( 'IllegalValue', $key, $result );
                    break;
                }
            }
        }
        return $result;
    }

    /**
     * For a given $enumType, give the label associated with the given $enumValue (const name in class definition)
     *
     * @param string $enumType
     * @param integer $enumValue
     * @return string
     */
    final public static function Label( $enumType, $enumValue )
    {
        $result = 'IllegalValue';

        if ( class_exists( $enumType, false ) )
        {
            $reflector = new ReflectionClass( $enumType );

            foreach( $reflector->getConstants() as $key => $val )
            {
                if ( $val == $enumValue )
                {
                    $result = $key;
                    break;
                }
            }
        }
        return $result;
    }
}
?>
Kris
I love it -- that's a great solution!
Josh