В php нет встроенных enumerator-ов.
Можно быстренько написать свои. Для этого нам понадобится версия php не ниже 7.4.
Для этого нам понадобится абстрактный класс, который умеет выполнять базовые операции со списком.
А именно:
- Инициализировать значения
- Получать массив ключей
- Получать массив значений
- Возвращать весь список элементов
В этом нам очень поможет функция get_class_vars
, которая возвращает список переменных класса.
Описываем абстрактный класс, а затем на его основе будем создавать нужные нам классы и будем правильно их инициализировать.
/**
* Описываем абстрактный класс, который умеет инициализировать список вариантов используя собственные статичные переменные
* Class ENum
*/
abstract class ENum {
/**
* Ленивый вариант для инициализации переменных.
* Можно использовать в случаях, когда нам не важно, какое именно уникальное значение хранить в переменной.
* После описания класса вызвать функцию
* <code>(static function(){ static::lazyInit(MyClassEnumElement::class); })->bindTo(null,MyClassEnum::class)();</code>
* @param string $class название класса, который должен быть использован для инициализации, должен быть расширением класса EnumElement
*/
protected static function lazyInit(string $class){
$a = get_class_vars(static::class);
$counter = 1;
foreach ($a as $key=>$value){
static::$$key = new $class($key,$counter++);
}
}
/**
* Функция, которая возвращает массив ключей
* @return string[]
*/
static function keys(){
/** @var EnumElement[] $a */
$a = get_class_vars(static::class);
/** @var string[] $res */
$res = [];
foreach ($a as $v){
$res[] = $v->key;
}
return $res;
}
/**
* Функция, которая возвращает массив значений
* @return string[]
*/
static function values(){
/** @var EnumElement[] $a */
$a = get_class_vars(static::class);
/** @var string[] $res */
$res = [];
foreach ($a as $v){
$res[] = $v->value;
}
return $res;
}
/**
* Функция, которая возвращает все элементы
* @return array
*/
static function elements(){
return get_class_vars(static::class);
}
}
После создания класса enumerator-а нам нужно сделать простейший класс его элемента. Этот класс просто хранит ключ и значение.
/**
* Описываем класс для элемента Enum
* Class EnumElement
*/
class EnumElement {
var string $key;
var $value;
public function __construct(string $key,$value) {
$this->key = $key;
$this->value = $value;
}
}
И всё. Это весь базовый код который необходим для работы.
Далее уже с их помощью выполняем нужную нам работу.
Пример
Привожу рабочий пример с использованием данных классов.
/**
* Создаём пустой класс, на который будем ссылаться в качестве типа переменной
* Class EType
*/
class EType extends EnumElement {}
/**
* Создаём enumerator, в котором идёт перечисление возможных вариантов
* Class ETypes
*/
class ETypes extends Enum{
// Перечисляем публичные типы
/** @var EType $TYPE1 первый тип */
static EType $TYPE1;
/** @var EType второй тип */
static EType $TYPE2;
/**
* Создаём приватный метод для инициализации переменных.
* Для случаев, когда нам важно значение переменных
*/
private static function init(){
self::$TYPE1 = new EType('TYPE1',1);
self::$TYPE2 = new EType('TYPE2',2);
}
}
// Вызываем первичную приватную инициализацию
// Подробнее можно почитать тут https://www.php.net/manual/ru/closure.bindto.php
(static function(){
static::init(); // используем этот вариант, когда нам важны значения ключей
//static::lazyInit(EType::class); // а этот, когда не важны
})->bindTo(null,ETypes::class)();
После того как наши enumerator-ы описаны, мы можем их использовать в своём коде.
/**
* Создаём класс, в котором хотим использовать enumerator
* Сlass MyClass
*/
class MyClass {
// Тут мы уже можем ссылаться на класс для описания нашего типа
/** @var EType тип класса */
var Etype $type;
/**
* И в конструкторе мы можем ссылаться на класс EType
* @param EType $_type
*/
public function __construct(EType $_type) {
$this->type = $_type;
}
/**
* Небольшая функция, которая как-то по разному работаем в зависимости от типа.
* В нашем случае просто выводит его название на человеческом языке
* @param EType $type
*/
function echoMyType(Etype $type){
switch ($type){
case ETypes::$TYPE1: echo 'Type 1'; break;
case ETypes::$TYPE2: echo 'Type 2'; break;
}
echo '<br/>';
}
}
// И далее во время работы с классом можем использовать наш enumerator для создания объектов
// На эту строчки PHPStorm не ругается, ему всё нравится, компилятору тоже.
$a = new MyClass(ETypes::$TYPE1);
$a->echoMyType($a->type); // Type 1
$a->type = ETypes::$TYPE2;
$a->echoMyType($a->type); // Type 2
/*
// Эти строчки не скомпилируются и IDE должна выдать предупрждение.
// В этой строчке PHPStorm выделит единицу с предупреждением "Expected parameter of 'EType', 'int' provided
$a = new MyClass(1);
// В следующей строчке будет предупреждение "Incompatible types: "Expected parameter of '\EType', 'int' provided"
$a->type = 5;
/**/
Весь код можно посмотреть у меня в gists https://gist.github.com/viktorgvozdikov/c77d1b3b019ad646b3228e6c3c95d567