Статьи

Автоматическая генерация PHP кода с Memio

Вы когда-нибудь задумывались о написании кода, отвечающего за автоматическое создание определенных классов, методов, свойств PHP? Читайте дальше, чтобы получить подробную информацию о том, когда именно автоматическая генерация кода может быть полезной и — что самое важное — как правильно ее реализовать с помощью библиотеки Memio .

Code Generation Hero Image

Концепция

Основная идея довольно проста. Вы пишете код, который будет создавать другие части кода, функции, переменные, классы, блоки документов и т. Д. Как вы делаете это на языке программирования (в нашем случае PHP), вы можете указать параметры, операторы if-else, циклы, и так далее.

Конечно, возможность создавать PHP-код автоматически не означает, что мы, разработчики, будем заменены. Но его можно использовать для формирования базовой структуры, которая впоследствии будет доработана человеком. Например, вместо копирования-вставки для подготовки начального набора классов в вашем приложении, вы можете использовать генератор.

Генерация кода уже используется в различных рамках. Посмотрите Symfony2 GeneratorBundle , консольные команды CakePHP или Laravel Artisan для примеров.

Генерация PHP классов с помощью Memio

Если вы хотите написать свой собственный скрипт, который генерирует PHP-код автоматически, одним из вариантов является использование библиотеки Memio . Хорошая вещь о Memio заключается в том, что он хорошо написан с использованием объектно-ориентированного кода. Вам не нужно писать целевой код в строках, работать над объединением строковых переменных и т. Д. Все делается путем создания экземпляров классов и вызова их методов. Шаблоны для самого выходного кода хранятся как шаблоны Twig.

Чтобы начать использовать Memio в своем проекте, просто добавьте его в файл composer.jsonдокументации . Основной класс, ответственный за генерацию кода — PrettyPrinterTwig_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 TABLESDESC <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);
}

И это все! Чтобы получить выходной код для класса, просто передайте переменную $classPrettyPrinter@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, вы можете дополнительно поместить выходной класс (класс ObjectFile Включение класса File в ваш скрипт Memio позволяет генерировать код с объявлением пространства имен, информацией о лицензии и открывающим тегом PHP в начале вывода. См. Документацию, чтобы проверить, как это можно реализовать, и попробуйте самостоятельно добавить соответствующий код. Чтобы получить все приложение на основе приведенного выше примера, просто проверьте репозиторий Github, связанный со статьей.

Следующие шаги

В нашем примере мы создали простой генератор классов, который отображает таблицы базы данных в объекты. Пример кода может быть расширен в гораздо более сложный скрипт. Например, вы можете использовать информацию о типах столбцов из MySQL и проверять переменные, которые передаются в методы установки. В качестве следующего шага вы можете сгенерировать код, который сохраняет объект в базе данных, передавая экземпляр объекта в оператор MySQL INSERTUPDATE

Также помните, что вывод скриптов на основе Memio можно изменить, изменив шаблоны по умолчанию. Например, если вы хотите сгенерировать код, который соответствует стандартам кодирования, используемым в вашем проекте, все, что вам нужно сделать, это внести изменения в шаблон. Тогда весь автоматически сгенерированный код будет создан на основе вашего собственного стиля кодирования и соглашений. Документация по шаблону содержит все подробности о том, как заменить шаблоны по умолчанию вашими файлами.

Я призываю вас самостоятельно написать несколько автоматически генерируемых скриптов, чтобы проверить все возможности библиотеки Memio. Поделитесь своими результатами и мыслями в комментариях ниже. Веселиться!