Comments 33
antanas-arvasevicius/enumerable-type — Строго типизированная реализация Enum.
Сколько себя помню :) всегда люди пытались реализовать Enum в PHP. Даже я пару раз пытался. Эта реализация выглядит лучше многих, но опять ограничения, прежде всего с десериализацией :( Что не так с PHP, что нельзя впилить такой тип в ядро?
Посмотрел код проекта. Оказалось все еще хуже чем я думал. Список доступных значений для ENUM получается с помощью рефлексии наследующего класса. Метод valueToString вообще мастерский говнокод.
Я ENUM в PHP рассматриваю как ValueObject и отношусь к нему соответствующе. В сущностях храню сам объект, а не его значение, список доступных значений описываю в явном виде и добавляю методы необходимыми для бизнеслогики.
enum — ValueObject или значения типа enum — ValueObject?
не очень понял вопрос.
Значение, для свойства объекта доменной области, может быть перечисление (enum). Для контроля за этим перечислением его удобно описать в виде объекта значения (ValueObject). Получается что-то вроде:
$my_type = TicketType::priority();
if ($ticket->type()->equals($my_type)) {
}
или так
if ($ticket->type()->isPriority()) {
}
все реализации ENUM в PHP через рефлексию. Так как у вас обычно классы ENUM условно маленькие а результат операции разумно кешируется во внутреннем поле, то накладные расходы весьма малы
Можно реализовать все тоже самое кеширование и прочие радости без рефлексии, явным образом реализовав метод или свойство которые возвращают список доступных значений.
Также можно добавить методы необходимые для бизнес логики и человеческое описание для вариантов значения для вывода на frontend. В случае использования подхода с рефлексией этого сделать нельзя.
Можно реализовать все тоже самое кеширование и прочие радости без рефлексии
это я не понял вообще
Также можно добавить методы необходимые для бизнес логики и человеческое описание для вариантов значения для вывода на frontend. В случае использования подхода с рефлексией этого сделать нельзя.
Это почему нельзя? что мне помешает?
Вообще всё что там дает рефлексия это убирает необходимость дублировать сами значения и как независимые единицы (в данном случае методы конструкторы) и в списке всех значений, что избавляет от дублирования и возможной человеческой ошибки. При этом как я и говорил ранее не особо нанося урон производительности.
Я вот пользуюсь реализацией myclabs/php-enum и там указываются константы.
Это почему нельзя? что мне помешает?
Пример на основе того же myclabs/php-enum. Я добавляю человеческое описание для вывода на frontend
class Action extends Enum
{
const VIEW = 'view';
const EDIT = 'edit';
// константы воспринимаются как варианты значения
// формат предназначен для перевода
const TITLE_VIEW = 'acme.demo.action.view';
const TITLE_EDIT = 'acme.demo.action.edit';
// можно использовать для radio/checkbox/select
public static function choices()
{
return [
self::VIEW => self::TITLE_VIEW,
self::EDIT => self::TITLE_EDIT,
];
}
public function title()
{
return static::choices()[$this->getValue()];
// можно былоб писать проще и не создавать метод choices,
// но тогда такую конструкцию тяжелее использовать для radio/checkbox/select
//return 'acme.demo.action.'.$this->getValue();
}
}
Можно не добавлять префикс для значения, но тогда теряется контекст. Одно и то же значение в разном контексте может по разному переводится.
Пример на основе antanas-arvasevicius/enumerable-type. Я добавляю свои методы для бизнеслогики
class Action extends EnumerableType
{
final public static View()
{
return static::get('view');
}
final public static Edit()
{
return static::get('edit');
}
// воспринимается как вариант значения
final public static equals(Action $action)
{
return $this->id() === $action->id();
}
}
Чёт я запутался… вы пишете:
… случае использования подхода с рефлексией этого сделать нельзя.
я с этим не согласился и потом вы мне приводите именно пример что можно! Что то пошло не так?
в случая же 2 вы как то сразу схитрили. Зачем метод делать final public static
? Да именно такие, и только такие, методы воспринимаются как значения. Ну ограничение той реализации. Точно так же как в myclabs/php-enum константы. Что особо не влияет на саму возможность делать
методы необходимые для бизнес логики и человеческое описание для вариантов значения для вывода на frontend.
я с этим не согласился и потом вы мне приводите именно пример что можно! Что то пошло не так?
Как раз я привожу пример что нельзя. myclabs/php-enum воспринимает константы с описанием как варианты значения. Тоесть метод Action::toArray()
вернет TITLE_VIEW
, что не корректно. Можно объявить TITLE_VIEW как не константу, но это все ухищрения чтоб угодить инструменту, а не бизнесу.
Хорошее решение этой проблемы предлагает библиотека marc-mabe/php-enum, которая воспринимает только публичные константы, но нужен PHP 7.1.
в случая же 2 вы как то сразу схитрили. Зачем метод делать final public static
?
Да, схитрил. Естественно. Потому что с точки зрения бизнеса не должно быть final
и не final
методов. Весь объект должен быть final
. А если инструмент требует помечать методы как final
, то я вынужден и остальные методы тоже помечать как final
, чтоб защитить класс.
Я хочу сказать, что используя подход с рефлексией, мы получаем автоматизацию генерации списка доступных значений (Action::choices()
), и в тоже время некоторые ограничения на использование методов или констант.
Создав один метод Action::choices()
вручную, мы сохраним все те же самые функции, но не будем иметь ограничений накладываемых рефлексией.
А… да по поводу непонимания мой косяк. Извиняюсь был невнимателен. День тяжелый.
Но всё же.
используя подход с рефлексией, мы получаем автоматизацию генерации списка доступных значений
Да, собственно я с этого начал. И да, вы правы ограничения есть, однако это не это не равно утверждению "с рефлексией этого сделать нельзя".
И да, вы правы ограничения есть, однако это не это не равно утверждению "с рефлексией этого сделать нельзя".
Если ограничения не позволяют нам что-то сделать, значит это сделать нельзя. Разве нет?
Если ограничения накладываются в результате использования рефлексии, то значит "с рефлексией этого сделать нельзя".
Вроде все логично.
Предлагаю подвести итоги.
Можно использовать как явное описание списка доступных значений, так и динамически генерируемое с помощью рефлексии. Оба вариант имеют свои плюсы и минусы. Я услышал ваше мнение и признаю, что вариант через рефлексию тоже имеет право на жизнь.
Попробовал реализацию через рефлексию. Оказалось действительно в чем-то удобнее. Спасибо что просветили.
Проблему с человеческим описанием в myclabs/php-enum можно решить так:
final class Action extends Enum
{
const VIEW = 'view';
const EDIT = 'edit';
// можно использовать для radio/checkbox/select
public static function choices()
{
$choices = [];
foreach (self::values() as $value) {
$choices[$value->getValue()] = (string) $value;
}
return $choices;
}
public function __toString()
{
return 'acme.demo.action.'.strtolower($this->getKey());
}
}
Но вот решил я сравнить производительность реализации через рефлексию и с явным описанием вариантов значений и получилось что рефлексия в 3-4 раза медленнее в зависимости от версии php.
$ php tests/benchmark.php 100000
Reflection enum: 1.25 MiB - 14079 ms
Reflection enum no magic: 1.25 MiB - 11286 ms
Explicit enum: 1.25 MiB - 3221 ms
Тест no magic это тест без использования магических функций __call()
и __callStatic()
и даже он оказывается медленнее в 3 раза.
Отсюда делаем вывод. За удобство нужно платить.
Хотелось бы взглянуть на бенчмарк полностью.
Вангую что нет кэша для рефлексий.
В целом же профит от enum-ов в возможности проверять по типам. Без этого смысла заморачиваться нет.
огорчу. кеш есть.
Для сравнения добавил в тест:
Результат:
$ php tests/benchmark.php 100000
Reflection enum: 1.25 MiB - 10401 ms
Reflection enum no magic: 1.25 MiB - 11382 ms
MyClabs enum: 1.25 MiB - 18531 ms
MarcMabe enum: 1.25 MiB - 11422 ms
MarcMabe enum no magic: 1.25 MiB - 11278 ms
HappyTypes enum: 1.50 MiB - 6992 ms
Explicit enum: 1.50 MiB - 2848 ms
Ошибся со ссылкой для happy-types/enumerable-type.
Я кинул пару PR в myclabs/php-enum, может вам пригодится
Отличная подборка в этот раз. Нашёл для себя новые штуки. Одно только огорчило:
Двухфакторная аутентификация в Laravel с помощью SMS (Twilio)
Не стоит рекламировать SMS в качестве фактора аутентификации. Дырявый канал.
Самый странный RFC который я видел, это кому то реально нужно?
-
Автору Maxlab/stacker большое спасибо, недавно начал осваивать Docker, а тут все и сразу да еще и с виде о описанием.
justinrainbow/json-schema не очень удобно использовать. thephpleague/json-guard как-то поприятнее.
Laravel Forge API — API сервиса теперь задокументировано. Имеется неофициальный клиент mpociot/blacksmith.
Пользуясь случаем попиарю свою реализацию API SDK — https://github.com/tzurbaev/laravel-forge-api :)
PHP-Дайджест № 104 – интересные новости, материалы и инструменты (1 – 12 марта 2017)