Вы когда-нибудь задумывались о написании кода, отвечающего за автоматическое создание определенных классов, методов, свойств PHP? Читайте дальше, чтобы получить подробную информацию о том, когда именно автоматическая генерация кода может быть полезной и — что самое важное — как правильно ее реализовать с помощью библиотеки Memio .
Концепция
Основная идея довольно проста. Вы пишете код, который будет создавать другие части кода, функции, переменные, классы, блоки документов и т. Д. Как вы делаете это на языке программирования (в нашем случае PHP), вы можете указать параметры, операторы if-else, циклы, и так далее.
Конечно, возможность создавать PHP-код автоматически не означает, что мы, разработчики, будем заменены. Но его можно использовать для формирования базовой структуры, которая впоследствии будет доработана человеком. Например, вместо копирования-вставки для подготовки начального набора классов в вашем приложении, вы можете использовать генератор.
Генерация кода уже используется в различных рамках. Посмотрите Symfony2 GeneratorBundle , консольные команды CakePHP или Laravel Artisan для примеров.
Генерация PHP классов с помощью Memio
Если вы хотите написать свой собственный скрипт, который генерирует PHP-код автоматически, одним из вариантов является использование библиотеки Memio . Хорошая вещь о Memio заключается в том, что он хорошо написан с использованием объектно-ориентированного кода. Вам не нужно писать целевой код в строках, работать над объединением строковых переменных и т. Д. Все делается путем создания экземпляров классов и вызова их методов. Шаблоны для самого выходного кода хранятся как шаблоны Twig.
Чтобы начать использовать Memio в своем проекте, просто добавьте его в файл composer.json
документации . Основной класс, ответственный за генерацию кода — PrettyPrinter
Twig_Environment
Его следует инициализировать следующим образом:
$twigLoaderFilesystem = new Twig_Loader_Filesystem('vendor/memio/memio/templates');
$twigEnvironment = new Twig_Environment($twigLoaderFilesystem, []);
$memioPrettyPrinter = new \Memio\Memio\PrettyPrinter($twigEnvironment);
Чтобы сгенерировать некоторый код PHP с помощью Memio, вам нужно создать объекты, которые представляют определенные части кода, а затем просто передать их экземпляру PrettyPrinter
Каждый из объектов, представляющих автоматически сгенерированный код, является экземпляром одного из классов model
Memio. Чтобы настроить выходной код, вам нужно вызвать определенные методы в этих случаях, а библиотека Memio сделает все остальное при печати. Добавление тела к методу, установка видимости свойства, установка интерфейса, который реализует класс, — все это делается путем вызова соответствующих методов. Вот пример создания класса User:
$class = \Memio\Memio\Model\Object::make('User');
$nameProperty = \Memio\Memio\Model\Property::make('name');
$class->addProperty($nameProperty);
$getNameMethod = \Memio\Memio\Model\Method::make('getName')->setBody('return $this->name');
$class->addMethod($getNameMethod);
echo $memioPrettyPrinter->generateCode($class);
Это даст следующий результат:
class User
{
private $name;
public function getName()
{
return $this->name;
}
}
Пример из реального мира: объектно-реляционное отображение
Автоматически генерируемый код PHP часто используется при сопоставлении структуры базы данных с классами PHP. Каждая таблица в базе данных может быть представлена отдельным классом в приложении PHP. Тогда каждый из столбцов таблицы будет представлен свойством класса. Давайте попробуем написать простой скрипт, который будет создавать такие классы на основе структуры базы данных MySQL.
Чтобы начать с нашего скрипта, нам нужно получить список таблиц в выбранной базе данных. Нам также понадобится список столбцов в каждой из этих таблиц. Чтобы получить все эти данные, мы должны использовать две команды MySQL: SHOW TABLES
DESC <table name>
Следующим шагом является создание отдельного класса PHP для каждой из таблиц. Имя класса будет таким же, как и имя таблицы, только начиная с заглавной буквы:
foreach($tableNames as $table) {
$class = new \Memio\Memio\Model\Object(ucfirst($table));
//...
}
Чтобы сделать наши классы более полезными, мы добавим свойства класса, представляющие каждый из столбцов таблицы. Предполагая, что мы сохранили имена столбцов в плоском массиве, код будет выглядеть следующим образом:
foreach($columnNames as $column) {
$property = \Memio\Memio\Model\Property::make($column);
$class->addProperty($property);
}
И это все! Чтобы получить выходной код для класса, просто передайте переменную $class
PrettyPrinter@generateCode
$code = $memioPrettyPrinter->generateCode($class);
Это позволяет нам автоматически генерировать классы для всех таблиц в нашей базе данных.
Расширение генератора моделей
Приведенный выше пример является простым введением в работу с Memio. Чтобы сделать наши классы более удобными в использовании, мы можем расширить их многими способами. Во-первых, давайте сгенерируем методы получения и установки для каждого из свойств. Наш цикл по именам столбцов в таблице теперь будет выглядеть следующим образом:
foreach($columnNames as $column) {
$property = \Memio\Memio\Model\Property::make($column);
$class->addProperty($property);
$getter = Method::make('get' . ucfirst($column))->setBody('return $this->' . $column . ';');
$class->addMethod($getter);
$setterArgument = Argument::make('string', $column);
$setter = Method::make('set' . ucfirst($column))->addArgument($setterArgument)->setBody('$this->' . $column . ' = $' . $column . ';');
$class->addMethod($setter);
}
Как видите, мы создали две переменные, которые создают экземпляр класса Memio Method
$getter
$setter
Имя методов, которые будут сгенерированы: get<Column>
set<Column>
Поскольку методу setter нужен аргумент, нам нужно создать экземпляр класса Memio Argument
Затем мы передаем его в наш метод setter, вызывая addArgument()
$setter
Следующим шагом является добавление тела в методы getter и setter, просто вызывая метод setBody()
Наконец, мы добавляем эти методы в класс, вызывая addMethod()
$class
В приведенном выше примере показан один важный аспект работы с Memio. Обратите внимание, что мы всегда передаем объекты, представляющие небольшие части кода, на объекты более высокого уровня. Сначала идет аргумент метода (класс Argument
Затем мы создаем метод (класс Method
$method->addArgument()
Метод должен быть помещен в класс, поэтому мы создаем класс (класс Object
$class->addMethod()
Таким образом, общая идея состоит в том, чтобы начать с небольших частей кода и связать их с контейнерами более высокого уровня.
Чтобы представить всю структуру кода в Memio, вы можете дополнительно поместить выходной класс (класс Object
File
Включение класса File в ваш скрипт Memio позволяет генерировать код с объявлением пространства имен, информацией о лицензии и открывающим тегом PHP в начале вывода. См. Документацию, чтобы проверить, как это можно реализовать, и попробуйте самостоятельно добавить соответствующий код. Чтобы получить все приложение на основе приведенного выше примера, просто проверьте репозиторий Github, связанный со статьей.
Следующие шаги
В нашем примере мы создали простой генератор классов, который отображает таблицы базы данных в объекты. Пример кода может быть расширен в гораздо более сложный скрипт. Например, вы можете использовать информацию о типах столбцов из MySQL и проверять переменные, которые передаются в методы установки. В качестве следующего шага вы можете сгенерировать код, который сохраняет объект в базе данных, передавая экземпляр объекта в оператор MySQL INSERT
UPDATE
Также помните, что вывод скриптов на основе Memio можно изменить, изменив шаблоны по умолчанию. Например, если вы хотите сгенерировать код, который соответствует стандартам кодирования, используемым в вашем проекте, все, что вам нужно сделать, это внести изменения в шаблон. Тогда весь автоматически сгенерированный код будет создан на основе вашего собственного стиля кодирования и соглашений. Документация по шаблону содержит все подробности о том, как заменить шаблоны по умолчанию вашими файлами.
Я призываю вас самостоятельно написать несколько автоматически генерируемых скриптов, чтобы проверить все возможности библиотеки Memio. Поделитесь своими результатами и мыслями в комментариях ниже. Веселиться!