PHP and Enumerations

后端 未结 30 1988
有刺的猬
有刺的猬 2020-11-22 13:39

I know that PHP doesn\'t have native Enumerations. But I have become accustomed to them from the Java world. I would love to use enums as a way to give predefined values whi

30条回答
  •  天涯浪人
    2020-11-22 14:10

    Four years later I came across this again. My current approach is this as it allows for code completion in the IDE as well as type safety:

    Base class:

    abstract class TypedEnum
    {
        private static $_instancedValues;
    
        private $_value;
        private $_name;
    
        private function __construct($value, $name)
        {
            $this->_value = $value;
            $this->_name = $name;
        }
    
        private static function _fromGetter($getter, $value)
        {
            $reflectionClass = new ReflectionClass(get_called_class());
            $methods = $reflectionClass->getMethods(ReflectionMethod::IS_STATIC | ReflectionMethod::IS_PUBLIC);    
            $className = get_called_class();
    
            foreach($methods as $method)
            {
                if ($method->class === $className)
                {
                    $enumItem = $method->invoke(null);
    
                    if ($enumItem instanceof $className && $enumItem->$getter() === $value)
                    {
                        return $enumItem;
                    }
                }
            }
    
            throw new OutOfRangeException();
        }
    
        protected static function _create($value)
        {
            if (self::$_instancedValues === null)
            {
                self::$_instancedValues = array();
            }
    
            $className = get_called_class();
    
            if (!isset(self::$_instancedValues[$className]))
            {
                self::$_instancedValues[$className] = array();
            }
    
            if (!isset(self::$_instancedValues[$className][$value]))
            {
                $debugTrace = debug_backtrace();
                $lastCaller = array_shift($debugTrace);
    
                while ($lastCaller['class'] !== $className && count($debugTrace) > 0)
                {
                    $lastCaller = array_shift($debugTrace);
                }
    
                self::$_instancedValues[$className][$value] = new static($value, $lastCaller['function']);
            }
    
            return self::$_instancedValues[$className][$value];
        }
    
        public static function fromValue($value)
        {
            return self::_fromGetter('getValue', $value);
        }
    
        public static function fromName($value)
        {
            return self::_fromGetter('getName', $value);
        }
    
        public function getValue()
        {
            return $this->_value;
        }
    
        public function getName()
        {
            return $this->_name;
        }
    }
    

    Example Enum:

    final class DaysOfWeek extends TypedEnum
    {
        public static function Sunday() { return self::_create(0); }    
        public static function Monday() { return self::_create(1); }
        public static function Tuesday() { return self::_create(2); }   
        public static function Wednesday() { return self::_create(3); }
        public static function Thursday() { return self::_create(4); }  
        public static function Friday() { return self::_create(5); }
        public static function Saturday() { return self::_create(6); }      
    }
    

    Example usage:

    function saveEvent(DaysOfWeek $weekDay, $comment)
    {
        // store week day numeric value and comment:
        $myDatabase->save('myeventtable', 
           array('weekday_id' => $weekDay->getValue()),
           array('comment' => $comment));
    }
    
    // call the function, note: DaysOfWeek::Monday() returns an object of type DaysOfWeek
    saveEvent(DaysOfWeek::Monday(), 'some comment');
    

    Note that all instances of the same enum entry are the same:

    $monday1 = DaysOfWeek::Monday();
    $monday2 = DaysOfWeek::Monday();
    $monday1 === $monday2; // true
    

    You can also use it inside of a switch statement:

    function getGermanWeekDayName(DaysOfWeek $weekDay)
    {
        switch ($weekDay)
        {
            case DaysOfWeek::Monday(): return 'Montag';
            case DaysOfWeek::Tuesday(): return 'Dienstag';
            // ...
    }
    

    You can also create an enum entry by name or value:

    $monday = DaysOfWeek::fromValue(2);
    $tuesday = DaysOfWeek::fromName('Tuesday');
    

    Or you can just get the name (i.e. the function name) from an existing enum entry:

    $wednesday = DaysOfWeek::Wednesday()
    echo $wednesDay->getName(); // Wednesday
    

提交回复
热议问题