Массивы PHP это мощный и многогранный инструмент. С его помощью можно создавать самые разные структуры данных. Чтоб код был понятным и читаемым нужно придерживаться стандартов. Вот несколько правил, которые я использую для работы с динамическими массивами. Это в большей степени «Руководство по стилю проектирования массивов».
Оглавление
- Использование списков в качестве массивов
- Использование массивов в качестве ассоциативных массивов
- Пользовательские классы коллекций
- Некоторые правила для пользовательских классов коллекций
Использование списков в качестве массивов
Все элементы должны быть одного типа
При использовании массива в качестве списка (набора значений с определенным порядком) каждое значение должно быть одного типа:
Общепринятый стиль аннотирования типа списка @var array<TypeOfElement> . Убедитесь, что вы не добавили тип индекса (он всегда должен быть int).
Игнорируйте индекс каждого элемента
PHP автоматически создает новые индексы для каждого элемента в списке (0, 1, 2 и т. Д.). Однако вы не должны полагаться на эти индексы или использовать их напрямую. Единственное свойство списка, на которое должны полагаться клиенты, - это то, что он является повторяемым и счетным.
Поэтому не бойтесь использовать foreach и count (), но не используйте for для циклической работы с элементами в списке:
(В PHP цикл for может даже не работать, потому что в списке могут отсутствовать индексы, или же количество индексов больше, чем количество элементов в списке.)
Вместо удаления элементов используйте фильтр
Вы можете удалить элементы из списка по их индексу (unset ()), но целесообразней использовать array_filter () вместо удаления элементов для создания нового списка без нежелательных элементов.
Опять же, не полагайтесь на индекс элементов, поэтому при использовании array_filter () вы не должны использовать параметр flag для фильтрации элементов на основе индекса или даже на основе как элемента, так и индекса.
Использование массивов в качестве ассоциативных массивов
Когда ключи актуальны и не являются индексами (0, 1, 2 и так далее) не бойтесь использовать массив как ассоциативный массив (коллекцию, из которой вы можете извлекать значения по их уникальному ключу).
Все ключи должны быть одного типа
Первое правило использования массивов в качестве ассоциативных массивов состоит в том, что все ключи в массиве должны быть одного типа (чаще всего это ключи строкового типа).
Все значения должны быть одного типа
То же самое происходит и со значениями: они должны быть одного типа.
Общепринятый стиль аннотирования типа:
@var array<TypeOfKey, TypeOfValue>
Ассоциативные массивы должны оставаться приватными
Списки можно безопасно передавать от объекта к объекту из-за их простых характеристик. Любой клиент может использовать его для циклического перебора или подсчёта элементов, даже если список пуст. С ассоциативными массивами работать сложнее, потому как клиенты могут полагаться на ключи, которые не имеют соответствующего значения. Это значит, что в целом они должны оставаться закрытыми для объекта, который ими управляет. Вместо того, чтобы позволять клиентам напрямую обращаться к внутренним ассоциативным массивам, предлагайте геттеры (и, возможно, сеттеры) для получения значений. Убирайте исключения, если значение для запрошенного ключа не существует. Однако, если вы можете полностью сохранить карту и ее значения, сделайте это.
Используйте объекты для ассоциативных массивов с несколькими типами значений
Если вы хотите использовать ассоциативные массивы, и при этом хранить в них различные типы значений, используйте объекты. Определите класс и добавьте к нему общедоступные типизированные свойства или же конструктор и геттеры. Примеры таких объектов - объекты конфигурации или объекты команд:
Исключения из этих правил
Иногда библиотеки или фреймворки требуют более динамичного использования массивов. В таких случаях невозможно (и нежелательно) следовать предыдущим правилам. Примерами являются массив данных, которые будут храниться в таблице базы данных, или конфигурация формы Symfony.
Пользовательские классы коллекций
Пользовательские классы коллекций могут быть очень крутым способом наконец поработать с Iterator, ArrayAccess и их «друзьями», но я считаю, что большая часть полученного кода, запутанная. Тем, кто впервые смотрит на код, придется поискать подробности в руководстве по PHP, даже если они опытные разработчики. Кроме того, вам нужно написать больше кода, который вы должны поддерживать (тестировать, отлаживать и т. д.). Поэтому в большинстве случаев я считаю, что простого массива с некоторыми соответствующими аннотациями типов вполне достаточно.
Как понять, что вам все-таки нужно превратить ваш массив в пользовательский объект коллекции?
- Вы обнаружите, что логика, связанная с этим массивом, скопирована.
- Вы обнаружите, что клиентам приходится иметь дело со слишком большим количеством подробностей о том, что находится внутри массива.
Используйте собственный класс коллекции для предотвращения дублирования логики
Если несколько клиентов, работающих с одним и тем же массивом, выполняют одну и ту же задачу (например, фильтруют, отображают, сокращают, подсчитывают), вы можете удалить это дублирование, введя собственный класс коллекции. Перемещение дублированной логики в метод класса коллекции позволяет любому клиенту выполнять ту же задачу, используя простой метод для вызова этой коллекции:
Преимущество использования метода преобразования в коллекции состоит в том, что преобразование получает имя. Это позволяет вам добавить короткую и содержательную метку к довольно сложному на вид array_filter ().
Используйте пользовательский класс коллекции для разделения клиентов
Если клиент, который работает с определенным массивом, перебирает его, извлекает часть данных из выбранных элементов и что-то делает с этими данными, этот клиент становится тесно связанным со всеми задействованными типами: самим массивом, типом элементов, которые находятся в массиве, типом значений, которые он извлекает из выбранных элементов, типом метода селектора и т. д. Проблема с такой глубокой связью состоит в том, что становится действительно сложно изменить что-либо в задействованных типах, не нарушая клиента, который от них зависит. Таким образом, в этом случае вы также можете обернуть массив в настраиваемый класс коллекции и давать правильный ответ за один раз, выполнив необходимые вычисления внутри и ослабив связь клиента с коллекцией.
Некоторые правила для пользовательских классов коллекций
Давайте посмотрим на некоторые правила, которые я применяю при работе с пользовательскими классами коллекций.
Сделайте их неизменными
Существующие ссылки на экземпляр коллекции не должны изменяться, если вы запускаете какое-либо преобразование для них. Следовательно, любой метод, выполняющий преобразование, должен возвращать новый экземпляр класса, как мы видели в примере выше:
Конечно, если вы преобразуете внутренний массив, сможете сопоставлять другой тип коллекции и простой массив. Убедитесь, что вы указали правильный тип возвращаемого значения.
Предлагайте только то поведение, которое нужно реальным клиентам и которое они используют
Вместо того, чтобы расширять общий класс библиотеки коллекции или самостоятельно реализовывать универсальный метод filter, map и reduce для каждого настраиваемого класса коллекции, реализуйте только то, что действительно необходимо. Если в какой-то момент метод перестает использоваться, удалите его.
Используйте IteratorAggregate и ArrayIterator для поддержки итерирования
Если вы работаете с PHP, вместо того, чтобы самостоятельно реализовывать все методы интерфейса Iterator (и сохранять внутренний указатель и т. д.), просто реализуйте интерфейс IteratorAggregate и позвольте ему вернуть экземпляр ArrayIterator на основе внутреннего массива:
Рассмотрим компромисс
Написание большего количества кода для вашего пользовательского класса коллекции должно облегчить клиентам работу с этой коллекцией (а не только с массивом). Если клиентский код становится проще для понимания, а коллекция обеспечивает полезное поведение, это оправдывает дополнительные затраты на поддержку настраиваемого класса коллекции.
Однако, поскольку с динамическими массивами так легко работать, в основном потому, что для элементов массива пока нету поддержки типов использовать их нужно аккуратно.
Дата: 12.01.2021 Автор: Евгений
|
|
Авторам статьи важно Ваше мнение. Будем рады его обсудить с Вами:
comments powered by Disqus