PHP и перечисления - PullRequest
       137

PHP и перечисления

1078 голосов
/ 31 октября 2008

Я знаю, что в PHP нет нативных перечислений. Но я привык к ним из мира Java. Я хотел бы использовать перечисления как способ дать предопределенные значения, которые могли бы понимать функции автозаполнения IDE.

Константы делают свое дело, но есть проблема столкновения пространства имен и (или на самом деле , потому что ) они глобальные. Массивы не имеют проблем с пространством имен, но они слишком расплывчаты, их можно перезаписать во время выполнения, и IDE редко (никогда?) Знают, как автоматически заполнять свои ключи.

Какие решения / обходные пути вы обычно используете? Кто-нибудь помнит, были ли у ребят из PHP какие-то мысли или решения по поводу перечислений?

Ответы [ 37 ]

1 голос
/ 15 января 2013

Указанное решение работает хорошо. Чисто и гладко.

Однако, если вы хотите строго типизированные перечисления, вы можете использовать это:

class TestEnum extends Enum
{
    public static $TEST1;
    public static $TEST2;
}
TestEnum::init(); // Automatically initializes enum values

С классом Enum, похожим на:

class Enum
{
    public static function parse($enum)
    {
        $class = get_called_class();
        $vars = get_class_vars($class);
        if (array_key_exists($enum, $vars)) {
            return $vars[$enum];
        }
        return null;
    }

    public static function init()
    {
        $className = get_called_class();
        $consts = get_class_vars($className);
        foreach ($consts as $constant => $value) {
            if (is_null($className::$$constant)) {
                $constantValue = $constant;
                $constantValueName = $className . '::' . $constant . '_VALUE';
                if (defined($constantValueName)) {
                    $constantValue = constant($constantValueName);
                }
                $className::$$constant = new $className($constantValue);
            }
        }
    }

    public function __construct($value)
    {
        $this->value = $value;
    }
}

Таким образом, значения перечисления строго типизируются и

TestEnum::$TEST1 === TestEnum::parse('TEST1') // true statement

0 голосов
/ 23 января 2018

Если вам нужна безопасность типов и набор констант, соответствующих этому типу, один из способов - создать абстрактный класс для вашего перечисления, а затем расширить этот класс с помощью заблокированного конструктора, например:

abstract class DaysOfWeekEnum{
    public function __construct(string $value){
        $this->value = $value; 
    }
    public function __toString(){
        return $this->value;
    }

}
class Monday extends DaysOfWeekEnum{
    public function __construct(){
        parent::__construct("Monday");
    }
}

class Tuesday extends DaysOfWeekEnum{
    public function __construct(){
        parent::__construct("Tuesday");
    }
}

Затем вы можете заставить ваши методы взять экземпляр DaysOfWeek и передать ему экземпляр понедельника, вторника и т. Д. но я считаю, что оно того стоит.

function printWeekDay(DaysOfWeek $day){
    echo "Today is $day.";
}

printWeekDay(new Monday());
0 голосов
/ 07 мая 2017

Более простая и легкая версия, в которой не используется отражение:

abstract class enum {
    private function __construct() {}
    static function has($const) {
        $name = get_called_class();
        return defined("$name::$const");
    }
    static function value($const) {
        $name = get_called_class();
        return defined("$name::$const")? constant("$name::$const") : false;
    }
}

Использование:

class requestFormat  extends enum { const HTML = 1; const JSON = 2; const XML  = 3; const FORM = 4; }

echo requestFormat::value('JSON'); // 2
echo requestFormat::has('JSON');   // true

Это дает преимущество констант, а также позволяет проверять их валидность, но в нем отсутствуют другие причудливые функциональные возможности, предоставляемые более сложными решениями, поскольку в этом вопросе более очевидна неспособность проверить обратную величину (в примере выше, вы не можете проверить, является ли '2' допустимым значением)

0 голосов
/ 30 марта 2017

Недавно я разработал простую библиотеку для перечислений PHP: https://github.com/dnl-blkv/simple-php-enum

На момент написания этого ответа он все еще находится на стадии подготовки к выпуску, но уже полностью функционален, хорошо документирован и опубликован на Packagist.

Это может быть удобным вариантом, если вы ищете простые в реализации перечисления, подобные C / C ++.

0 голосов
/ 03 мая 2012

Я использую конструкцию, подобную следующей, для простых перечислений. Обычно вы можете использовать их для операторов switch.

<?php 
  define("OPTION_1", "1");
  define("OPTION_2", OPTION_1 + 1);
  define("OPTION_3", OPTION_2 + 1);

  // Some function...
   switch($Val){
    case OPTION_1:{ Perform_1();}break;
    case OPTION_2:{ Perform_2();}break;
    ...
  }
?>

Это не так удобно, как нативное перечисление, как в C ++, но, кажется, работает и требует меньшего количества обслуживания, если позже вы захотите добавить опцию между ними.

0 голосов
/ 28 августа 2012

Моя попытка создать перечисление с помощью PHP ... оно чрезвычайно ограничено, поскольку не поддерживает объекты в качестве значений перечисления, но все же несколько полезно ...

class ProtocolsEnum {

    const HTTP = '1';
    const HTTPS = '2';
    const FTP = '3';

    /**
     * Retrieve an enum value
     * @param string $name
     * @return string
     */
    public static function getValueByName($name) {
        return constant('self::'. $name);
    } 

    /**
     * Retrieve an enum key name
     * @param string $code
     * @return string
     */
    public static function getNameByValue($code) {
        foreach(get_class_constants() as $key => $val) {
            if($val == $code) {
                return $key;
            }
        }
    }

    /**
     * Retrieve associate array of all constants (used for creating droplist options)
     * @return multitype:
     */
    public static function toArray() {      
        return array_flip(self::get_class_constants());
    }

    private static function get_class_constants()
    {
        $reflect = new ReflectionClass(__CLASS__);
        return $reflect->getConstants();
    }
}
0 голосов
/ 14 января 2015
// My Enumeration Class
class Enum
{
    protected $m_actions = array();

    public function __construct($actions)
    {
        $this->init($actions);
    }

    public function init($actions)
    {
        $this->m_actions = array();
        for($i = 0; $i < count($actions); ++$i)
        {
            $this->m_actions[$actions[$i]] = ($i + 1); 
            define($actions[$i], ($i + 1));
        }
    }

    public function toString($index)
    {
        $keys = array_keys($this->m_actions);
        for($i = 0; $i < count($keys); ++$i)
        {
            if($this->m_actions[$keys[$i]] == $index)
            {
                return $keys[$i];
            }
        }

        return "undefined";
    }

    public function fromString($str)
    {
        return $this->m_actions[$str];
    }
}

// Enumeration creation
$actions = new Enum(array("CREATE", "READ", "UPDATE", "DELETE"));

// Examples
print($action_objects->toString(DELETE));
print($action_objects->fromString("DELETE"));

if($action_objects->fromString($_POST["myAction"]) == CREATE)
{
    print("CREATE");
}
...