Я знаю, что в PHP нет нативных перечислений. Но я привык к ним из мира Java. Я хотел бы использовать перечисления как способ дать предопределенные значения, которые могли бы понять функции автозаполнения IDE.
Константы делают свое дело, но есть проблема коллизий пространства имен и (или на самом деле потому что ) они глобальные. Массивы не имеют проблем с пространством имен, но они слишком расплывчаты, их можно перезаписать во время выполнения, и IDE редко (никогда?) Знают, как автоматически заполнять свои ключи.
Есть ли какие-либо решения / обходные пути, которые вы обычно используете? Кто-нибудь помнит, были ли у ребят из PHP какие-то мысли или решения по поводу перечислений?
php
enumeration
Хенрик Пол
источник
источник
Ответы:
В зависимости от варианта использования, я бы обычно использовал что-то простое, например:
Однако в других случаях использования может потребоваться дополнительная проверка констант и значений. Основываясь на комментариях ниже о рефлексии и нескольких других примечаниях , вот расширенный пример, который может лучше служить гораздо более широкому кругу случаев:
Создав простой класс enum, который расширяет BasicEnum, вы теперь можете использовать методы для простой проверки ввода:
В качестве примечания: каждый раз, когда я использую отражение хотя бы один раз в классе static / const, где данные не изменятся (например, в enum), я кеширую результаты этих вызовов отражения, так как каждый раз использую свежие объекты отражения в конечном итоге окажет заметное влияние на производительность (хранится в ассоциативном массиве для нескольких перечислений).
Теперь, когда большинство людей наконец-то обновилось до версии не ниже 5.3 и
SplEnum
стало доступным, это, безусловно, приемлемый вариант - если вы не возражаете против традиционно не интуитивного представления о наличии фактических экземпляров перечисления в вашей кодовой базе. В приведенном выше примереBasicEnum
иDaysOfWeek
не могут быть созданы вообще, и они не должны быть.источник
abstract
иfinal
, таким образом, его нельзя создать или расширить.abstract
иfinal
? Я знаю, на Java это не разрешено. Вы можете сделать это в php?abstract
иfinal
. В этом случае я бы пошел на абстракцию.null
и друзьями вswitch
утверждении. Был там.Также есть нативное расширение. SplEnum
http://www.php.net/manual/en/class.splenum.php
Внимание:
https://www.php.net/manual/en/spl-types.installation.php
источник
А как насчет классовых констант?
источник
echoConstant
можно заменить на__toString
. А потом простоecho $c
Верхний ответ выше фантастический. Тем не менее, если вы
extend
это двумя различными способами, то, какое бы расширение ни делалось первым, в результате вызов к функциям создаст кеш. Этот кэш будет затем использоваться всеми последующими вызовами, независимо от того, какое расширение вызовы инициируют ...Чтобы решить эту проблему, замените переменную и первую функцию на:
источник
Я использовал классы с константами:
источник
Я использую
interface
вместоclass
:источник
class Foo implements DaysOfWeek { }
а потомFoo::Sunday
... что?class
(илиinterface
, это просто вопрос предпочтений).Я прокомментировал некоторые другие ответы здесь, поэтому я решил, что я тоже буду взвешивать. В конце концов, поскольку PHP не поддерживает типизированные перечисления, вы можете пойти одним из двух способов: взломать типизированные перечисления или смириться с тем фактом, что их чрезвычайно трудно эффективно взломать.
Я предпочитаю жить с фактом, и вместо этого использовать
const
метод, который так или иначе использовали другие ответы здесь:Пример перечисления:
Использование в
Enum
качестве базового класса , от которого всех остальных перечислений расширения позволяет вспомогательные методы, такие какtoArray
,isValid
и так далее. Для меня типизированные перечисления ( и управление их экземплярами ) просто оказываются слишком запутанными.гипотетический
Если существовал
__getStatic
магический метод ( и желательно__equals
магический метод тоже ), большая часть этого могла бы быть смягчена с помощью своего рода многотонных схем.( Следующее является гипотетическим; это не сработает, хотя, возможно, однажды это сработает )
источник
Ну, для простого java-подобного enum в php я использую:
И назвать это:
Но я новичок в PHP, борюсь с синтаксисом, так что это может быть не лучшим способом. Я экспериментировал с константами классов, используя Reflection, чтобы получить имя константы из ее значения, может быть лучше.
источник
Четыре года спустя я снова столкнулся с этим. Мой текущий подход заключается в следующем: он допускает завершение кода в IDE, а также безопасность типов:
Базовый класс:
Пример Enum:
Пример использования:
Обратите внимание, что все экземпляры одной и той же записи перечисления одинаковы:
Вы также можете использовать его внутри оператора switch:
Вы также можете создать запись enum по имени или значению:
Или вы можете просто получить имя (то есть имя функции) из существующей записи enum:
источник
const Monday = DaysOfWeek('Monday');
Я нашел эту библиотеку на github, и я думаю, что она предоставляет очень приличную альтернативу ответам здесь.
Реализация PHP Enum вдохновлена SplEnum
function setAction(Action $action) {
format
,parse
...)final
чтобы предотвратить это)декларация
Применение
значения перечисления type-hint:
источник
enum
будет добавлен PHP 7.x), потому что он позволяет подсказки типа.__toString()
магии позволяет делать то, что вы обычно хотите, с помощью перечислений - использовать их в выраженииswitch
илиif
, сравнивая непосредственно со значениями констант. Лучший подход, за исключением поддержки родного enum, IMO.Если вам нужно использовать перечисления, которые глобально уникальны (т.е. даже при сравнении элементов между разными перечислениями) и просты в использовании, не стесняйтесь использовать следующий код. Я также добавил несколько методов, которые я считаю полезными. Вы найдете примеры в комментариях в самом верху кода.
источник
eval()
только для того, чтобы вы могли объявить новое время выполнения Enums? Ик. Я этого не чувствую. Как вы препятствуете другим классам создавать неправильный класс Enum, прежде чем вы сможете определить правильный? Разве Enums не известны до выполнения? И, как подразумевает @corsiKa, автозаполнение IDE отсутствует. Единственное преимущество, которое я вижу, - это ленивое кодирование.Мне также нравятся перечисления из java, и по этой причине я пишу свои перечисления таким образом, я думаю, что это самое похожее поведение, как в перечислениях Java, конечно, если кто-то хочет использовать больше методов из java, следует написать его здесь, или в абстрактный класс, но основная идея встроена в код ниже
источник
FruitsEnum::Apple()
болееFruitsEnum::$Apple
, но более важной причиной является то, чтобы не допустить никого из установки$APPLE
, тем самым нарушая перечисление для всего приложения. Другой - это простой закрытый статический флаг,$initialized
который гарантирует, что вызовinit()
становится недоступным после первого вызова (так что никто не может возиться с этим)..init()
странно, и я не возражаю против подхода получателя.источник
Это может быть так же просто, как
в будущем.
PHP RFC: перечисляемые типы
источник
Наиболее распространенным решением, которое я видел для enum в PHP, было создание универсального класса enum, а затем его расширение. Вы могли бы взглянуть на это .
ОБНОВЛЕНИЕ: В качестве альтернативы, я нашел это на phpclasses.org.
источник
Вот библиотека github для обработки перечислений, безопасных для типов в php:
Эта библиотека обрабатывает генерацию классов, кэширование классов и реализует шаблон проектирования Type Safe Enumeration с несколькими вспомогательными методами для работы с перечислениями, такими как получение порядкового номера для сортировки перечислений или извлечение двоичного значения для комбинаций перечислений.
В сгенерированном коде используется обычный старый файл шаблона php, который также настраивается, поэтому вы можете предоставить свой собственный шаблон.
Это полный тест, покрытый phpunit.
php-enums на github (не стесняйтесь форк)
Использование: (@see use.php или юнит-тесты для более подробной информации)
Вывод:
источник
Я воспользовался приведенным ниже подходом, так как он дает мне возможность обеспечить безопасность типов для параметров функций, автоматическое заполнение в NetBeans и хорошую производительность. Одна вещь, которая мне не очень нравится, это то, что вам нужно позвонить
[extended class name]::enumerate();
после определения класса.источник
DaysOfWeek::$MONDAY = 3;
[extended class name]::enumerate();
после определения, почему бы вам не сделать это в конструкции?Мое определение класса Enum ниже строго типизировано и очень естественно для использования и определения.
Определение:
Переключить Enum
Передайте Enum в качестве параметра (строго типизированный)
Echo Enum как строка
Получить Enum по целому числу
Получить Enum по имени
Класс Enum:
прибавление
Вы также можете добавить комментарии для IDE.
источник
Я понимаю, что это очень-очень-очень старая тема, но я подумал об этом и хотел узнать, что думают люди.
Примечания: я поиграл с этим и понял, что если я просто изменю
__call()
функцию, вы сможете приблизиться к реальнойenums
.__call()
Функция обрабатывает все неизвестные вызовы функций.enums
Допустим, вы хотите сделать три RED_LIGHT, YELLOW_LIGHT и GREEN_LIGHT. Вы можете сделать это сейчас, просто выполнив следующее:После определения все, что вам нужно сделать, это вызвать их снова, чтобы получить значения:
и вы должны получить 0, 1 и 2. Удачи! Это также сейчас на GitHub.
Обновление: я сделал так, что теперь используются
__get()
и__set()
функции, и. Это позволяет вам не вызывать функцию, если вы этого не хотите. Вместо этого теперь вы можете просто сказать:Для создания и получения ценностей. Поскольку переменные не были определены изначально,
__get()
вызывается функция (потому что не указано значение), которая видит, что запись в массиве не была сделана. Таким образом, он делает запись, присваивает ей последнее заданное значение плюс один (+1), увеличивает переменную последнего значения и возвращает TRUE. Если вы установите значение:Затем
__set()
вызывается функция, а последнему значению присваивается новое значение плюс один (+1). Так что теперь у нас есть довольно хороший способ делать перечисления, и их можно создавать на лету.источник
Я знаю, что это старый поток, однако ни один из обходных путей, которые я видел, на самом деле не выглядел как перечисления, так как почти все обходные пути требуют, чтобы вы вручную присваивали значения элементам перечисления, или он требует, чтобы вы передавали массив ключей перечисления функция. Поэтому я создал собственное решение для этого.
Чтобы создать класс enum с использованием моего решения, можно просто расширить этот класс Enum ниже, создать группу статических переменных (не нужно их инициализировать) и сделать вызов yourEnumClass :: init () чуть ниже определения вашего класса enum ,
edit: это работает только в php> = 5.3, но, вероятно, может быть изменено для работы в более старых версиях
источник
Теперь вы можете использовать класс SplEnum для его создания. Согласно официальной документации.
Обратите внимание, это расширение, которое должно быть установлено, но не доступно по умолчанию. Подпадает под специальные типы, описанные на самом сайте php. Приведенный выше пример взят с сайта PHP.
источник
Наконец, ответ PHP 7.1+ с константами, которые нельзя переопределить.
Если вы используете пространства имен, завершение кода должно работать.
Однако при этом вы теряете возможность скрывать константы в пределах класса family (
protected
) или одного класса (private
). По определению, все вInterface
являетсяpublic
.Руководство по PHP: Интерфейсы
источник
Это мой взгляд на "динамическое" перечисление ... так что я могу вызывать его с переменными, напр. из формы.
посмотрите обновленную версию ниже этого кодового блока ...
ОБНОВЛЕНИЕ: лучший способ сделать это ...
Позвонить с
источник
EnumCategory::$sport = 9;
, Добро пожаловать в музей спорта.const
это лучший способ сделать это.Принятый ответ - это путь, и на самом деле я делаю это для простоты. Предлагается большинство преимуществ перечисления (читабельное, быстрое и т. Д.). Однако отсутствует одна концепция: безопасность типов. В большинстве языков перечисления также используются для ограничения допустимых значений. Ниже приведен пример того, как безопасность типов также можно получить с помощью частных конструкторов, статических методов создания экземпляров и проверки типов:
Мы могли бы даже пойти дальше: использование констант в классе DaysOfWeek может привести к неправильному использованию: например, можно ошибочно использовать это следующим образом:
что неправильно (вызывает целочисленную константу). Мы можем предотвратить это, используя закрытые статические переменные вместо констант:
Конечно, невозможно получить доступ к целочисленным константам (это и было целью). Метод intVal позволяет преобразовать объект DaysOfWeek в его целочисленное представление.
Обратите внимание, что мы могли бы даже пойти дальше, реализовав механизм кэширования в методах создания экземпляров, чтобы сэкономить память в случаях, когда перечисления широко используются ...
Надеюсь, это поможет
источник
Некоторые хорошие решения здесь!
Вот моя версия.
Я думаю, что основным недостатком является то, что члены enum должны быть объявлены и созданы отдельно из-за описаний и неспособности PHP создавать объекты во время статического объявления членов. Я думаю, что можно обойти это путем использования отражения с проанализированными комментариями к документу.
Абстрактное перечисление выглядит так:
Вот пример конкретного перечисления:
Который можно использовать так:
И производит этот вывод:
источник
Не используйте отражение. Это крайне затрудняет анализ вашего кода и отслеживание того, где что-то используется, и имеет тенденцию ломать инструменты статического анализа (например, то, что встроено в вашу IDE).
источник
Одним из аспектов, отсутствующих в некоторых других ответах, здесь является способ использования перечислений с подсказками типов.
Если вы определяете свое перечисление как набор констант в абстрактном классе, например,
тогда вы не можете напечатать подсказку в параметре функции - например, потому что это не может быть создано, но также потому, что тип
ShirtSize::SMALL
isint
, а неShirtSize
.Вот почему родные перечисления в PHP были бы намного лучше, чем все, что мы можем придумать. Однако мы можем приблизить перечисление, сохранив частное свойство, которое представляет значение перечисления, а затем ограничив инициализацию этого свойства нашими предопределенными константами. Чтобы предотвратить создание произвольного экземпляра перечисления (без дополнительных затрат на проверку типов в белом списке), мы делаем конструктор закрытым.
Тогда мы можем использовать
ShirtSize
так:Таким образом, самым большим отличием с точки зрения пользователя является то, что вам нужно добавить
()
имя константы.Один недостаток - это то, что
===
(который сравнивает равенство объектов) вернет false, когда==
вернет true. По этой причине, то лучше предоставитьequals
метод, так что пользователи не должны помнить , чтобы использовать==
и не===
сравнивать два перечисляемых значения.РЕДАКТИРОВАТЬ: несколько существующих ответов очень похожи, в частности: https://stackoverflow.com/a/25526473/2407870 .
источник
Шагнув на ответ @Brian Cline, я подумал, что могу дать свои 5 центов
источник
include('enums.php');
. Почему-то он не видит функции, объявленные в Enum для дочерних классов ...$currentSeason.set("Spring");
Моя попытка создать enum с помощью PHP ... она чрезвычайно ограничена, поскольку она не поддерживает объекты в качестве значений enum, но все же несколько полезна ...
источник
Вчера я написал этот класс в своем блоге . Я думаю, что это может быть легко для использования в PHP-скриптах:
Применение:
источник