Каков рекомендуемый способ создания enum-подобного поведения в PHP 7? - PullRequest
2 голосов
/ 24 апреля 2019

Удивительно, но в PHP нет встроенной поддержки перечислений. В PHP 5.4 нативное расширение SPL_Types можно использовать для эмуляции этого поведения с SplEnum, но последнее обновление этого расширения было в 2012 году. В PHP 7 при попытке установить расширение будут возникать ошибки компиляции из-за измененных интерфейсов.

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

enum DaysOfTheWeek
{
    Monday = 1,
    Tuesday = 2,
    Wednesday = 3,
    Thursday = 4,
    Friday = 5,
    Saturday = 6,
    Sunday = 7
}

$day = DaysOfTheWeek::Monday;
echo $day; //Prints 1

Мой текущий код выглядит менее лаконичным и содержит много (ненужных) накладных расходов:

class DayOfTheWeek
{
    private __value;

    const Monday = 1;
    const Tuesday = 2;
    const Wednesday = 3;
    const Thursday = 4;
    const Friday = 5;
    const Saturday = 6;
    const Sunday = 7;

    public function __construct(int $value)
    {
        if ($value !== DayOfTheWeek::Monday
            && $value !== DayOfTheWeek::Tuesday
            && $value !== DayOfTheWeek::Wednesday
            && $value !== DayOfTheWeek::Thursday
            && $value !== DayOfTheWeek::Friday
            && $value !== DayOfTheWeek::Saturday
            && $value !== DayOfTheWeek::Sunday
        )
        {
            throw new InvalidArgumentException("Invalid day of the week");
        }
    }

    public function GetValue(): int
    {
        return $this->__value;
    }
}

Некоторые уточнения:

Почему бы не использовать абстрактный класс с несколькими постоянными значениями?

Поскольку это полностью опровергает идею хинтинга типов в PHP 7. Идея состоит в том, что я могу сказать функции принять экземпляр этого перечисления и быть уверенным в том, что это допустимое значение.

Почему бы вам не оптимизировать дни недели? Вы можете упростить проверку, посмотрев, находится ли она между 0 и 6.

Потому что перечисления не имеют в порядке или не показывают никакого отношения друг к другу. Перечисление может иметь значения 56, 1999, 120, -12400, 8, -1239 и 44. Код для перечисления не должен зависеть от значений перечисления.

1 Ответ

1 голос
/ 24 апреля 2019

Я бы по-прежнему использовал массив, но на основе ReflectionClass , чтобы проверить, определено ли данное значение в константах класса

<?
class DayOfTheWeek
{
    private $__value;
    private $__day;

    const Monday = 1;
    const Tuesday = 2;
    const Wednesday = 3;
    const Thursday = 4;
    const Friday = 5;
    const Saturday = 6;
    const Sunday = 7;

    public function __construct(int $value)
    {
        $myClass = new ReflectionClass ( get_class($this) );
        $constants = $myClass->getConstants();
        foreach($constants as $dayName=>$dayValue) {
            if($value === $dayValue) {
                $this->__day = $dayName;
                $this->__value = $dayValue;
                break;
            }
        }
        if(is_null($this->__day)) {
            throw new InvalidArgumentException("Invalid day of the week");
        }
    }

    public function GetValue(): int
    {
        return $this->__value;
    }
}

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

$return = new DayOfTheWeek(5);
var_dump($return);

Вывод:

object(DayOfTheWeek)#1 (2) {
  ["__value":"DayOfTheWeek":private]=>
  int(5)
  ["__day":"DayOfTheWeek":private]=>
  string(6) "Friday"
}

Я не был уверен в проблемах с производительностью, но обнаружил это на SO

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...