В PHP 8.1 наконец-то добавили встроенную поддержку перечислений — enum. Под катом — перевод статьи блогера и PHP разработчика ​​Брента с обзором новых возможностей, дополнениям и комментариями разработчиков о том, что они думают о поддержке перечислений в PHP 8.1. Enum в PHP ждали — и новая функция оправдывает ожидания. Сергей Пешалов, инженер-программист из Eggheads Solutions, оценил нововведения так: Если раньше фактически писался свой класс или просто использовали массив, то сейчас для этого есть enum. Смысл в том, что в БД поле enum было, а в php нет, поэтому для реализации использовали каждый во что горазд. Сейчас эту проблему решили. Реализация интересная. Фактически перечислители работают как классы, даже с методами. Очень удобно. Раз удобно, давайте разберёмся подробнее в том, как работают перечисления. Так выглядят перечисления: Преимущество enum в том, что это набор постоянных значений, которые можно вводить так: В этом примере мы создаём enum и передаём его BlogPost объекту так: Хотя кейсы enum сами по себе являются объектами, их нельзя создавать с помощью new. Кроме того, перечисления  имеют фиксированное количество возможных значений.  Enum могут определять методы, как и обычные классы. Это очень мощная функция, особенно в сочетании с оператором match: Методы можно использовать так: Также разрешены статические методы: Self в перечислениях тоже применяют: Одно из наиболее важных различий между enum и классом заключается в том, что enums не могут иметь состояния. Объявление свойств для перечислений запрещены, также не допускаются статические свойства. Перечисления полностью поддерживают все магические константы, которые PHP поддерживает для классов. Константа класса, которая ссылается на имя самого enum: __CLASS__  —магическая константа, которая ссылается на имя enum из enum. __FUNCTION__  —в контексте метода enum. __METHOD__  — в контексте метода enum. Чтобы объекты enum не имели какого-либо состояния и чтобы два enum были сопоставимы, enums запрещает реализацию нескольких магических методов: __get (): чтобы предотвратить сохранение состояния в объектах enum. __set (): чтобы предотвратить присвоение динамических свойств и поддержания состояния. __construct (): перечисления не поддерживают все конструкции new Foo (). __destruct (): перечисления не должны поддерживать состояние. __clone (): перечисления — это неклонируемые объекты. __sleep (): перечисления не поддерживают методы жизненного цикла. __wakeup (): перечисления не поддерживают методы жизненного цикла. __set_state (): чтобы предотвратить принуждения состояния к объектам enum. Enum могут реализовывать интерфейсы, как и обычные классы: Перечисления, не поддерживаемые значением, автоматически реализуют интерфейс UnitEnum. Перечисления не могут явно реализовать этот интерфейс, поскольку это делается внутри движка. Это делается только для помощи в определении типа данных enum. Метод UnitEnum :: cases возвращает массив всех случаев данного enum. Хотя enum — это объект, вы можете присвоить им значения, чтобы сохранить их в базе данных. Перечисления поддерживают пространства имён, автозагрузку, методы, но не свойства, реализующие интерфейсы и другое поведение PHP-классов. Обратите внимание на объявление типа в определении перечислений. Так мы указываем, что все значения enum относятся к заданному типу. Аналогичным образом работает int. В качестве значений enum можно использовать только int и string.  Любой другой тип, включая типы bool, null, String, Int, не допускается. Если вы решите присвоить значения перечислениям, это необходимо сделать для каждого перечисления, также типы нельзя смешивать и совмещать. PHP резервирует enum и предотвращает создание любых функций, классов, интерфейсов и так далее с именем enum. PHP учитывает зарезервированные ключевые слова в значениях пространства имён.  Синтаксис аналогичен синтаксису трейта/класса/интерфейса. Само имя enum нечувствительно к регистру и соответствует тому, как PHP обрабатывает классы и функции без учёта регистра.  Максим Епихин, руководитель отдела поддержки и тестирования программного обеспечения АСУ, ФГАНУ ЦИТиС: Enum — это отличная система организации списков. Вот такой класс я писал для этого раньше, когда перечислений не было. Он который имитирует часть enum. Сейчас я могу от него полностью избавиться. То есть все статичные данные, которые я храню классами и наследованием и интерфейсами, просто заменились на нормальный и лаконичный enum. Теперь можно было бы хранить все enum не классами (как костыль), а средствами языка.  С одной стороны, количество файлов не изменится, а просто заменятся классы на enum. С другой стороны, зачем хранить файлы, если enum можно объявлять в одном файле. Тут другая проблема: enum будут в одном файле, а это неудобно для изменения и поиска. Главная фича в том, что мы избавляемся от своих костылей в пользу ядра движка с готовыми функциями, но получаем энтропию организации enum. Enum нельзя наследовать от другого enum или его класса. Если класс пытается расширить enum, это также приведёт к ошибке, потому что все enum объявлены окончательными. Если вы комбинируете типизированные enum с интерфейсами, тип перечисления нужно ставить сразу после имени перечисления, перед ключевым словом implements. Если вы присваиваете значения вариантам перечислений, вам понадобится способ их сериализации и десериализации. Сериализация означает, что вам нужен способ получить значение перечисления. Это делается с помощью общедоступного свойства value — только для чтения: Получить значение перечисления можно с помощью метода :Enum::from: Также можно использовать метод tryFrom, который вернёт null, если передано неизвестное значение. При использовании from будет выведено исключение: Обратите внимание, при работе с перечислениями можно использовать встроенную функцию serialize и unserialize. Кроме того, можно использовать json_encode в сочетании с типизированными перечислениями, результатом функции и будет значение enum. Это поведение можно изменить, реализовав JsonSerializable. Чтобы получить все доступные варианты перечислений, воспользуйтесь статичным методом :Enum::cases(): Обратите внимание, в массиве содержатся объекты перечисления: Варианты перечислений — это объекты, на самом деле это одноэлементные объекты. Сравнить их можно так: Так как перечисления — объекты, сейчас их невозможно использовать в качестве ключей массива. Такой код приведёт к ошибке: RFC предлагает изменить это поведение, но за него ещё не проголосовали. Пока вы можете использовать перечисления только в качестве ключей в SplObjectStorage и WeakMaps. Перечисления могут использовать трейты аналогично классам, но с некоторыми ограничениями. Вы не можете переопределять встроенные методы перечислений, а также они не могут содержать свойства класса, что запрещено в перечислениях. PHP поддерживает автозагрузку для классов, трейтов и интерфейсов, enums также поддерживает автозагрузку. Обратите внимание, что для этого могут потребоваться обновления генераторов карт классов, которые анализируют файлы на предмет автоматически загружаемых элементов. Для работы с enum добавили несколько Reflection классов: ReflectionEnum, ReflectionEnumUnitCase и ReflectionEnumBackedCase. Также добавили новую функцию enum_exists — функция, название которой говорит само за себя. Обратите внимание, что из-за семантики классов функция class_exists также возвращает true для enum. Как и обычные классы и свойства, enum и их случаи можно аннотировать с помощью атрибутов. Обратите внимание, enum включат в фильтр TARGET_CLASS. И последнее: у перечислений также есть readonly свойство: $enum->name, которое в RFC упоминают как деталь реализации и, вероятно, его можно использовать только для отладки.  Епихин Максим Николаевич, руководитель отдел поддержки и тестирования программного обеспечения АСУ, ФГАНУ ЦИТиС: Очень крутая и долгожданная вещь в PHP. Минусы и нюансы только в добавлении элементов. Это, насколько мне известно, не такая «дешёвая» операция. Несколько вариантов сравнения, которые работают как бы одинаково, но кто-то умудрится запороть всё и там. Пока протестировать их не удалось, но думаю, что именно в этом будут проблемы.  Проводник Нетологии на Хабре