PHP Profi

Чего всё ещё не хватает в PHP: generics Перевод

php generic

РНР 7.2 не за горами, и эта версия принесёт нам такие изменения в типах, как возможность указать тип object в сигнатуре методов, или как расширение типа параметра.
Они подтверждают желание сообщества PHP укрепить систему типов в PHP и улучшить безопасность типов.

В Libcast (видеохостинг), мы ценим эти изменения, которые позволяют полагаться на IDE, которая отображает ошибки типов при вводе кода и проверяет типы во время компиляции, тем самым уменьшая время, необходимое для поиска и исправления ошибки.
Дженерики (Generics) - это фича, которая, как мы надеемся, скоро появятся в PHP и позволит создавать универсальные контейнеры указанного типа.

Дженерики (Generics)

Generic-классы позволяют объявить универсальный контейнер, тип которого должен быть задан во время использования (нельзя использовать общий класс - сам generic).
Для специализации generic-класса, может быть использован любой тип, если он соответствует сигнатуре в универсальном (generic) классе.

Generic-класс может использовать несколько generic-типов, или быть частично специализирован, задав только часть generic-типов.

Дженерики(Generics) в PHP

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);
    }
}

Дженерики связаны со всеми концепциями типизации, о которых мы, возможно, поговорим в следующих статьях.

Ссылки:

2017-11-28 irul оригинал
General Food

Комментарии

авторизуйтесь, чтобы оставить комментарий