Квест → Как хакнуть форму
Прошли: 77
РНР 7.2 не за горами, и эта версия принесёт нам такие изменения в типах, как возможность указать тип object
в сигнатуре методов, или как расширение типа параметра.
Они подтверждают желание сообщества PHP укрепить систему типов в PHP и улучшить безопасность типов.
В Libcast (видеохостинг), мы ценим эти изменения, которые позволяют полагаться на IDE, которая отображает ошибки типов при вводе кода и проверяет типы во время компиляции, тем самым уменьшая время, необходимое для поиска и исправления ошибки.
Дженерики (Generics) - это фича, которая, как мы надеемся, скоро появятся в PHP и позволит создавать универсальные контейнеры указанного типа.
Generic-классы позволяют объявить универсальный контейнер, тип которого должен быть задан во время использования (нельзя использовать общий класс - сам generic).
Для специализации generic-класса, может быть использован любой тип, если он соответствует сигнатуре в универсальном (generic) классе.
Generic-класс может использовать несколько generic-типов, или быть частично специализирован, задав только часть generic-типов.
Generics-RFC всё ещё в черновике и не был принят.
Hack/HHVM уже реализовал дженерики.
ircmaxell провели эксперимент среди пользователей РНР, как говорится "just for fun" (не используйте это в продакшен, конечно).
Дженерики будут полезны в PHP для таких контейнеров: абстрактный тип данных (стек, очередь, карта ...), и контейнеров вашей предметной области (список дней, группа людей ...).
Также они позволяют иметь более точные сигнатуры: на данный момент, PHP имеет iterable
для возможности объявить коллекцию в сигнатуре, но объявление generic-iterable
позволит сказать, что мы просим коллекцию именно книг.
Мы создали заглушку для нового API видеоплатформы Libcast, в котором мы должны генерировать случайные данные, но иногда следовать некоторым правилам (указанному распределению).
Например, мы хотим генерировать события нашей предметной области, каждое из которых с указанным шансом возникновения — для того, чтобы моделировать более реалистичные данные в заглушке.
Мы хотели бы также создавать фиктивных посетителей в соответствии с реальным географическим распределением в нашей нынешней базе посетителей.
Наиболее напрашивающейся для нас является возможность выделить в общий класс ту часть, где выбор делается по распределению.
Вот упрощенный первый вариант классов для обработки приведенных примеров:
// Generates IP addresses final class IpGenerator { public function generate(string $countryCode = 'FR'): Ip { // ... } } final class DistributedIpGenerator { /** @var IpGenerator */ private $generator; /** @var array */ private $distribution; public function __construct(IpGenerator $generator, array $distribution) { $this->generator = $generator; $this->distribution = $distribution; } public function generate(): Ip { // Pick a country code wisely // $countryCode = ... return $this->generator->generate($countryCode); } } // Generate domain events final class EventGenerator { public function generate(string $eventType): Event { } } final class DistributedEventGenerator { /** @var EventGenerator */ private $generator; /** @var array */ private $distribution; public function __construct(EventGenerator $generator, array $distribution) { $this->generator = $generator; $this->distribution = $distribution; } public function generate(): Event { // Pick an event type wisely // $eventType = ... return $this->generator->generate($eventType); } }
DistributedIpGenerator
и DistributedEventGenerator
классы практически идентичны, за исключением сигнатур и возвращаемых типов.
С дженириками мы могли бы использовать всего один класс:
class DistributedGenerator { /** @var callable */ private $generator; /** @var array */ private $distribution; public function __construct(callable $generator, array $distribution) { $this->generator = $generator; $this->distribution = $distribution; } public function generate(): DataType { // Pick a value wisely // $value = ... return $this->generator($value); } }
Этот класс может стать даже более специализированным, если мы хотим генерировать события таких типов: UserEvent
, VideoEvent
....
Обратите внимание, что вы также можете включить тип генератора в список типов дженериков. Но попробуем справиться с помощью нескольких имплементаций для генераторов:
class DistributedGenerator { /** @var GeneratorType */ private $generator; /** @var array */ private $distribution; public function __construct(GeneratorType $generator, array $distribution) { $this->generator = $generator; $this->distribution = $distribution; } public function generate(): DataType { // Pick a value wisely // $value = ... // This part would change for each GeneratorType: return $this->generator->whatever($value); } }
Дженерики связаны со всеми концепциями типизации, о которых мы, возможно, поговорим в следующих статьях.
Ссылки:
Идея клевая, но придется тогда пожертвовать скоростью работы или переходить на использование компиляции.
Ну не совсем.
Пре-компиляция в байт-код и сейчас есть. Если при пре-компиляции будут генерироваться готовые конечные классы, которые используются в данном приложении (а скорее всего так и будут реализовывать), то скорость исполнения не увеличится. Немного возрастёт время пре-компиляции в байт-код, но это будет на столько не существенно, что не отразится на скорости в общем. А с учётом того, что пре-компилированный код кешируется, то разницы не будет вообще.