- PVSM.RU - https://www.pvsm.ru -
Помимо многих проблем, в PHP существует проблема строгой типизации переменных и свойств классов, точнее её отсутствие. Более того, нет даже возможности однозначно задать какие будут свойства у объектов того или иного класса, пользуясь только синтаксисом и не прибегая к так называемым магическим методам (потому что любое свойство может быть удалено при помощи оператора unset, а также к объекту может быть дописано несуществующее ранее свойство).
Однако при разработке часто возникает потребность в чётком знании, что можно ожидать от объекта, а чего можно не ожидать. Разумеется, можно пойти простым путём: сделать все свойства protected и понаписать геттеров и сеттеров. Много бойлерплейта, хочется проще. Лично я пытался решить эту проблему с помощью трейтов, но выходило всё равно некрасиво. Так и появилась идея этого проекта…
Кому интересно, добро пожаловать под кат!
Проект PHP-DataGen[1] [1] является утилитой — генератором кода PHP классов с определёнными свойствами и направлен на упрощение работы PHP программистов. Инструмент имеет как возможность управлять генерацией с помощью PHP скриптов, так и CLI для работы со встроенным парсером собственного языка (далее — PDGL).
Из соображений удобства использования целевой аудиторией (PHP программисты), для разработки был выбран язык PHP.
Версия последнего на данный момент релиза — v0.2.2-alpha. В скором времени планируется версия v0.3-alpha, в связи с расширением функционала. К моменту выхода стабильного релиза планируется переписать весь «низкокачественный» код (написанный без достаточной квалификации), но пока всё и так работает.
В рамках данного обзора я рассмотрю основные аспекты использования утилиты.
Проект рассматривается в состоянии последнего на данный момент коммита 55bb922f7b739477f8eebdfdf3664e25e57f9168[2] [2].
На данный момент PHP-DataGen поддерживает 2 собственные команды: compile и build. Первая используется для поштучной компиляции файлов, вторая для компиляции всех файлов в проекте (директории). Использование команд максимально интуитивное и может быть изучено вручную благодаря библиотеке Symfony Console[6] [3], на которой основан CLI.
Также планируется добавить работу с файлом конфигурации для управления деталями процесса компиляции. При этом будет добавлено считывание файла конфигурации из корня проекта и команда config для удобного изменения конфигурации проекта.
До начала разработки было несколько идей по поводу внедрения утилиты в проекты:
Так как изначально проект создавался «по образу и подобию» утилиты moc популярного C++ фреймворка Qt, в приоритете был второй вариант, однако после некоторых раздумий, первые два варианта были отброшены мной как неоправданно сложные для реализации.
PDGL предназначен для описания файлов PHP, которые получаются на выходе PHP-DataGen. Каждый файл можно представить в виде дерева, отдалённо напоминающего абстрактное синтаксическое дерево[3] [4], которое состоит лишь из трёх типов узлов: файл, класс, поле.

Все поддерживающиеся языком операторы представлены в файле schema.md[4] [5] в корне проекта, но без описания, что делает тот или иной оператор. Операторы namespace и use работают также как и в обычном PHP, однако с классом, полями и их модификаторами всё не так просто.
Из модификаторов класса можно выделить лишь один нестандартный для PHP модификатор final, который также имеет вариацию final!. Дело в том, что результат работы PHP-DataGen — класс, который для работы должен быть расширен с помощью другого класса.
Модификатор final превращает класс в готовый для непосредственного использования, путём убирания префикса (по умолчанию, пока что без возможности изменения, Data_) и модификатора abstract итогового PHP класса.
Модификатор final!, который «под капотом» именуется не иначе как «final final» является дополнением к модификатору final (и не может быть использован без него) и добавляет к итоговому PHP классу модификатор final.
Синтаксис поля класса очень мало похож на синтаксис свойств PHP и даже больше, на мой взгляд, напоминает синтаксис свойств классов Kotlin.
Начнём с того, что написано в файле schema.md[4] [5]:
// Field declaration
[direct] <val/var> <Field name>[: <Type name>[, <Validator names>]][ <:/</>= [`[``]]<Default value>[`[``]]];
А теперь по порядку (операторы выделены жирным, подстановки — курсивом):
protected вместо private);$);mixed;string?), тогда поле может хранить также значение null;<=, := или = — оператор присваивания значения по-умолчанию. В вариации <= присваивает значение при объявлении свойства. В вариации := присваивает значение при вызове конструктора без проверки типа и вызова валидаторов. В вариации = присваивает значение при вызове конструктора с проверкой типа и вызовом валидаторов;;) (кроме случаев, когда используется вариация оператора присваивания значения по-умолчанию <=). Нет разницы в использовании ` или ```, если в значении по-умолчанию не присутствует символов обратного апострофа (`), в этом случае необходимо использовать оператор ```.Для лучшей фильтрации возможных значений полей планируется ввести возможность добавлять свои валидаторы — функции проверки (или модификации) значения. При том что в коде PHP-DataGen обработка валидаторов присутствует, пока нет способа добавлять их. Это одна из возможностей, которые должны появиться с появлением чтения конфигурации.
В самом начале реализации идеи начался длительный «ступор» связанный с отсутствием продуманной архитектуры и, как следствие, неправильно выбранным порядком разработки. Вскоре после появления ясности в голове — зарождения в голове архитектуры будущего инструмента, была начата разработка.

Упрощённая архитектура утилиты
На схеме выше изображена очень упрощённая архитектура PHP-DataGen. Она состоит из четырёх модулей:
Если до появления цельной архитектуры я (безуспешно) пытался написать Parser, то сразу после её появления я взялся за модуль Builders. Затем были написаны модели и Compiler. Таким образом, уже через два дня появился рабочий прототип, позволяющий генерировать код с помощью PHP скрипта.
Далее предстояло написать Parser. Из-за незнания об абстрактных синтаксических деревьях[3] [4], ломать голову пришлось долго. В итоге получился конечный автомат[5] [7], имеющий 3 состояния (которые также состоят из некоторых собственных состояний): FileState, ClassState и FieldState. Каждое из этих состояний при помощи соответствующих билдеров создаёт модели для Compiler.
В проекте используются следующие библиотеки:
Проект разрабатывался при помощи следующих инструментов:
Также, при написании статьи, для рисования диаграмм, использовался онлайн сервис Creately[8] [9].
75974bee3b4cccd1af1722acac775d68011f7fa6 — GitHub [11];Автор: Эридан Доморацкий
Источник [18]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/programmirovanie/284680
Ссылки в тексте:
[1] [1]: #link1
[2] [2]: #link2
[3] [6]: #link6
[4] [3]: #link3
[5] [4]: #link4
[6] следующий раздел: #validators
[7] [5]: #link5
[8] [7]: #link7
[9] [8]: #link8
[10] php-datagen — GitHub: https://github.com/ProgMiner/php-datagen
[11] 75974bee3b4cccd1af1722acac775d68011f7fa6 — GitHub: https://github.com/ProgMiner/php-datagen/tree/75974bee3b4cccd1af1722acac775d68011f7fa6
[12] Абстрактное синтаксическое дерево — Википедия: https://ru.wikipedia.org/wiki/Абстрактное_синтаксическое_дерево
[13] Файл schema.md — GitHub: https://github.com/ProgMiner/php-datagen/blob/master/schema.md
[14] Теория вычислений. Введение в конечные автоматы — Хабр: https://habr.com/post/358304/
[15] The Console Component — Symfony Docs: http://symfony.com/doc/current/components/console
[16] The Finder Component — Symfony Docs: http://symfony.com/doc/current/components/finder
[17] Creately: https://creately.com/
[18] Источник: https://habr.com/post/415861/?utm_source=habrahabr&utm_medium=rss&utm_campaign=415861
Нажмите здесь для печати.