В этой статье мы рассмотрим некоторые распространённые проблемы, связанные с массивами в PHP. Все проблемы могут быть решены с помощью RFC, добавляющего в PHP дженерики. Мы не будем сильно углубляться в то, что такое дженерики, но к концу статьи вы должны понять, чем они полезны и почему многие так ждут их появления в PHP.  Допустим, у вас есть набор блог-постов, скачанных из какого-то источника данных. Вам нужно циклически пройти по всем постам и что-то сделать с их данными. Например, с id. Это распространённый сценарий, на примере которого мы обсудим роль дженериков и то, почему сообщество так нуждается в них. Рассмотрим проблемы, возникающие при таком сценарии. В PHP массив представляет собой коллекцию ... элементов. Если циклически пройти по нашему набору постов, то в результате получим критическую ошибку. Вызываем ->getId() применительно к строке 'foo'. Не прокатило. При циклическом проходе по массиву мы хотим быть уверены, что все значения принадлежат к определённому типу. Можно сделать так: Это будет работать, но если вы уже писали PHP-код для production, то знаете, что такие проверки иногда быстро разрастаются и загрязняют кодовую базу. В нашем примере можно проверять тип каждой записи в методе ->find() в $blogModel. Но это лишь переносит проблему из одного места в другое. Хотя ситуация чуть улучшилась. С целостностью структуры данных есть ещё одна сложность. Допустим, у вас есть метод, которому нужен массив блог-постов: Мы опять можем добавить в цикл дополнительные проверки, но это не гарантирует, что $posts содержит только коллекцию постов Posts. Начиная с PHP 7.0 для решения этой проблемы вы можете использовать оператор ...: Но у этого подхода есть обратная сторона: вам придётся вызывать функцию применительно к распакованному массиву. Можно предположить, что лучше заранее знать, содержит ли массив только элементы определённого типа, чем потом в каждом цикле каждый раз вручную проверять типы. Мы не можем прогнать на дженериках бенчмарки, потому что их пока нет, так что остаётся лишь гадать, как они повлияют на производительность. Но не будет безумием предположить, что оптимизированное поведение PHP, написанное на С, — это лучший способ решения проблемы по сравнению с созданием кучи кода для пользовательского пространства. Не знаю, как вы, а я при написании PHP-кода прибегаю к IDE. Автозавершение чрезвычайно повышает продуктивность, так что я хотел бы использовать его и здесь. При циклическом проходе по постам нам нужно, чтобы IDE считал каждый $post экземпляром Post. Давайте посмотрим на простую PHP-реализацию: Начиная с PHP 7.0 появились типы возвращаемых значений, а в PHP 7.1 они были улучшены с помощью void и типов, допускающих значение null. Но мы никак не можем сообщить IDE, что содержится в массиве. Поэтому мы возвращаемся к PHPDoc. При использовании реализации «дженерика», например класса моделей (model class), не всегда возможен подсказывающий метод ->find(). Так что в нашем коде придётся ограничиться подсказывающей переменной $posts. Неуверенность в содержимом массива и влиянии разбросанности кода на производительность и удобство сопровождения, а также неудобство написания дополнительных проверок заставили меня долго искать решение получше. На мой взгляд, такое решение — дженерики. Не буду подробно расписывать, что они делают, об этом вы можете почитать в RFC. Но я приведу пример того, как дженерики могут помочь в решении вышеописанных проблем, всегда обеспечивая наличие в коллекции корректных данных. Важное замечание: дженериков пока что нет в PHP. RFC предназначен для PHP 7.1, о его будущем нет никакой дополнительной информации. Нижеприведённый код основан на интерфейсах Iterator и ArrayAccess, которые существуют с PHP 5.0. В конце мы разберём пример с дженериками, представляющий собой фиктивный код. Для начала создадим класс Collection, который работает в PHP 5.0+. Этот класс реализует Iterator, чтобы можно было циклически проходить по его элементам, а также ArrayAccess, чтобы можно было использовать «массивоподобный» синтаксис для добавления элементов коллекции и обращения к ним. Теперь можем воспользоваться подобным классом: Обратите внимание: нет никакой гарантии, что $collection содержит только Posts. Если добавить, к примеру, строковое значение, то работать будет, но наш цикл сломается. При текущем уровне развития PHP мы можем решить эту проблему с помощь создания класса PostCollection. Обратите внимание: типы возвращаемых данных, допускающие использование null, доступны лишь с PHP 7.1. Теперь в нашу коллекцию могут добавляться только Posts. Работает! Даже без дженериков! Есть только одна проблема: решение немасштабируемое. Вам нужны отдельные реализации для каждого типа коллекции, даже если классы будут различаться только типом.  Вероятно, создавать подклассы можно с бо́льшим удобством, «злоупотребив» поздним статическим связыванием и рефлексивным API PHP. Но вам в любом случае понадобится создавать классы для каждого доступного типа. Учитывая всё это, давайте рассмотрим код, который мы могли бы написать, будь дженерики реализованы в PHP. Это может быть один класс, используемый для всех типов. Ради удобства я приведу лишь изменения по сравнению с предыдущим классом Collection, имейте это в виду. И всё! Мы используем <T> в качестве динамического типа, который можно проверять перед runtime. И опять же, класс GenericCollection можно было бы брать для любых типов. Если вы так же впечатлены дженериками, как и я (а это лишь верхушка айсберга), то ведите просветительскую работу в сообществе и делитесь RFC: https://wiki.php.net/rfc/generics ¯\_(ツ)_/¯