Когда надоело запоминать ключи массивов и хочется пользоваться подсказками любимого редактора кода на помощь приходит PHPDoc и немного смекалки.

Недавно я очень близко познакомился с TypeScript и познал всю прелесть строгой типизации. Как же это приятно, когда редактор кода подсказывает тебе какие поля есть в объекте и что ты с ними можешь сделать!

В чем проблема?

Я работаю с CMS Битрикс и приходится иметь дело с массивами разной формы и содержания, запоминать все ключи или искать их в документации. Это занимает драгоценное время.

Решение:

Первым делом на ум приходит использовать PHPDoc, но тут появляется проблема:

/**
 * int[]
 * array
 * array<string>
 */

Нельзя прописать многомерный массив так, чтобы подсказывал редактор кода. Все найденные мной варианты не работают в VSCode и PhpStorm.

Недолго погуглив я нашёл вариант, который заработал только в VSCode.

/**
 * @var array $arr $arr
 * @var array $arr['fields']
 * @var array $arr['fields']['fieldName']
 * @var array $arr['fields']['fieldName']['name']
 * @var array $arr['fields']['fieldName']['model']
 * @var array $arr['fields'][fieldName]['width']
 * @var array $arr['fields'][fieldName]['align']
 * @var array $arr['fields'][fieldName]['format']
 * @var array $arr['fields'][fieldName]['title']
 * @var array $arr['fields'][fieldName]['desc']
 * @var array $arr['fields'][fieldName]['readonly']
 * @var array $arr['fields'][fieldName]['type']
 * @var array $arr['fields'][fieldName]['options']
 * @var array $arr['fields'][fieldName]['editor']
 * @var array $arr['fields'][fieldName]['default']
 **/
$arr = [
    'fields' => [
        'fieldName' => []
    ]
];

В таком случае среда подсказывает какой ключ можно выбрать:

Для PhpStorm есть плагин deep-assoc-completion, он требует описания массива в определённом формате:

/**
 * @var array $arr = [
 *     'fields' => [ // Defines the feilds to be shown by scaffolding
 *         $anyKey => [
 *             'name' => 'sale', // Overrides the field name (default is the array key)
 *             'model' => string, // (optional) Overrides the model if the field is a belongsTo associated value.
 *             'width' => '100px', // Defines the width of the field for paginate views. Examples are "100px" or "auto"
 *             'align' => 'center', // Alignment types for paginate views (left, right, center)
 *             'format' => 'nice', // Formatting options for paginate fields. Options include ('currency','nice','niceShort','timeAgoInWords' or a valid Date() format)
 *             'title' => 'Sale', // Changes the field name shown in views.
 *             'desc' => 'A deal another person that results in money', // The description shown in edit/create views.
 *             'readonly' => false, // True prevents users from changing the value in edit/create forms.
 *             'type' => 'password', // Defines the input type used by the Form helper
 *             'options' => ['option1', 'option2'], // Defines a list of string options for drop down lists.
 *             'editor' => false, // If set to True will show a WYSIWYG editor for this field.
 *             'default' => '', // The default value for create forms.
 *         ],
 *     ],
 * ]
 */
$arr=[
    'fields' => [
        '0' => [
            'model' => 2
        ]
    ]
];

В таком случае среда подсказывает ключи:

Остаётся одна проблема, если мы хотим таких подсказок, нам нужно делать подобное описание в каждом файле, где есть наш массив. Особенно актуально для Битрикса.

Моё решение:

Редактор кода хорошо индексирует объекты, так почему бы нам не привести массив к объекту и описать его?! Но как описать объект без класса, ведь PHPDoc в этом тоже помощник?

Мы можем создать класс, в котором опишем все нужные нам поля. И вот наш редактор уже подсказывает нам.

Хорошо, а дальше? Многомерные массивы мы можем описать так же как описываем интерфейсы в TS. Либо выносим вложенный массив в отдельный класс:

Либо прописываем в конструкторе текущего класса:

Обратите внимание, конструктор делаем приватным, чтобы нам не мешался, а вложенному полю обязательно создаём описание. Но PHPStorm его не поймёт.

Резюме

Вариант конечно запарный, но люди, пишущие на TS и так это уже давно делают. Если есть вариант получше, буду рад рассмотреть. И самое главное, смысл не в том, что так надо делать всегда, а в том, что если других вариантов нет (ограничены по времени и т.д. и т.п.), то можно применить эту технологию.

Комментарии (10)


  1. NiceDay
    23.02.2022 04:15
    +12

    поздравляю, вы изобрели Data Transfer Object


  1. NiceDay
    23.02.2022 04:33
    +11

    вот только изобрели не до конца. имеет смысл сразу и использовать созданный класс, а не пытаться обмануть IDE.

    И самое главное, смысл не в том, что так надо делать всегда, а в том, что если других вариантов нет (ограничены по времени и т.д. и т.п.), то можно применить эту технологию.

    смысл как раз в том, что описывать данные классами стоит как можно чаще.
    ну без фанатизма, но вы поймите, массивы это как раз от бедности, когда нужно быстро и можно тяп-ляп. массивы в PHP это очень мощный инструмент и использовать его можно абсолютно по-разному, поэтому и используют его кто на что горазд. но если мы хотим, чтоб проект был поддерживаемым, а люди, с ним работающие, не себе рвали волосы в труднодоступных местах, то использование DTO это очень замечательная практика.

    посмотреть хорошие практики, как это реализовать и использовать, можно например, тут - https://github.com/spatie/data-transfer-object


    1. shushu
      23.02.2022 07:09
      +3

      Lost case (c)

      Что бы применить DTO наверное надо весь битрикс переписывать, к сожалению. Я нивкоем случае не говорю что решение с ПхпДок - лучше. Я говорю про то - что там уже ничего не сделаешь...


      1. seyfer
        23.02.2022 11:05
        +4

        Вы можете массивы битрикса в свои dto оборачивать и работать с ними. И когда надо обратно в массив, добивать в каждом dto метод toArray. Т.е. dto может реализовывать даже https://www.php.net/manual/en/class.jsonserializable.php


        1. shushu
          23.02.2022 12:33
          +3

          Я и не отрицаю что можно. Вопрос в том, сколько усилий надо потратить что бы привести это в более менее нормальный вид?


  1. Bone
    23.02.2022 10:48

    В самой новой версии PHPStorm (2021.2 EAP) есть поддержка вложенных array shapes https://blog.jetbrains.com/phpstorm/2022/02/phpstorm-2022-1-eap-3/


    1. shushu
      23.02.2022 12:34
      +1

      В самой новой версии PHPStorm (2021.2 EAP)

      2022 до сих пор не привычно писать, ага?)


  1. Maquire
    23.02.2022 13:58
    +3

    Вы сейчас изобрели DTO, или я не уловил суть?


  1. masterWeber
    23.02.2022 13:58
    +3

    А почему нельзя просто использовать #[ArrayShape]?


  1. BigC777
    24.02.2022 11:10
    +2

    как ты можешь называть себя программистом, работая с ссаным битриксом?