Latte: как насчет системы типов?

5 лет назад от David Grudl  

Система типов. Ключевой аспект для разработки надежных приложений, в котором PHP значительно опередил динамические языки, такие как Python, Ruby или JavaScript. Фреймворк Nette с самого начала направлял программистов к типизированному и строгому программированию. Latte 2.7 принес поддержку типов и в шаблоны.

Благодаря тому, что мы знаем, какой тип данных или объекта находится в каждой переменной,

  • IDE может правильно подсказывать
  • статический анализ может выявлять ошибки

Два пункта, которые кардинально повышают качество и удобство разработки.

Как объявлять типы на стороне PHP?

Мы будем передавать данные в шаблон как объект класса, который определяет все переменные и их типы. С использованием новых возможностей PHP 7.4 он мог бы выглядеть так:

class MailTemplate
{
	public string $lang = 'cs';
	public Address $address;
	public string $subject;
	public ?float $price = null;
}

Использование:

$template = new MailTemplate;
$template->price = $this->getPrice();
...
$latte->render('mail.latte', $template);

Дополнение: благодаря новым возможностям PHP 8 пример можно записать еще интереснее:

class MailTemplate
{
	public function __construct(
		public string $lang = 'cs',
		public Address $address,
		public string $subject,
		public ?float $price = null,
	) {}
}

$latte->render('mail.latte', new MailTemplate(
	lang: $this->lang,
	subject: $title,
	price: $this->getPrice(),
	address: $userAddress,
));

Как объявлять типы в шаблоне?

Теперь мы можем связать указанный класс с шаблоном. Достаточно указать в начале:

{templateType MailTemplate}

И этим мы определили, что в шаблоне будет четыре переменных $lang, $address, $subject и $price с соответствующими типами.

Альтернативой является определение типов отдельных переменных прямо в шаблоне, то есть без создания класса. Для этого служит тег {varType}:

{varType string $lang}
{varType Address $address}

Конечно, можно комбинировать оба подхода. Создать класс, чтобы обеспечить подсказки на стороне презентера, связать его с шаблоном с помощью {templateType} и для остальных локальных переменных в блоках и т.д. использовать {varType}. Которые можно рассматривать как аналог /** @var type $variable */, комментария, которым мы иногда инструктируем IDE или статический анализатор в PHP коде.

Теперь тип можно указать также в тегах {var}, {default} или {define}:

{var Model\Page $page = $items['page']}
{define form, string $name}
	...
{/define}

Примечание: по историческим причинам в тегах {var} и {default} можно было писать переменные и без начального знака доллара (и со стрелкой вместо знака равенства). Поскольку это создает неоднозначность, является ли это типом или переменной, этот синтаксис запрещен, и Latte будет предупреждать вас при его использовании. Простой способ найти в своих шаблонах эту старую запись — это поиск по регулярным выражениям /\{(var|default) [^$]/ и /\{(var|default) [^}]*=>/.

Как сэкономить время?

Как проще всего написать класс шаблона или теги {varType}? Позвольте им сгенерироваться. Именно для этого существуют два тега: {templatePrint} и {varPrint}.

Если вы разместите один из этих тегов в шаблоне, вместо обычного рендеринга отобразится предложение кода класса или список тегов {varPrint} соответственно. Затем достаточно одного клика, чтобы выделить код и скопировать его в проект.

В nette/application 3.1 (в бета-версии) включен перегруженный тег {templatePrint}, который генерирует код, лучше адаптированный для презентеров.

Тег {varPrint} выводит локальные переменные, которые не являются параметрами шаблона. Если вы хотите вывести все переменные, используйте {varPrint all}.

Автодополнение в IDE

Последняя версия плагина Latte для PhpStorm умеет использовать вышеупомянутые теги и затем подсказывать на основе типов. Плагин также знает типы стандартных переменных, таких как $user, $presenter, $basePath и т.д.

Статический анализ

Цель состоит в том, чтобы все объявленные типы можно было использовать также для статического анализа. Чтобы, например, с помощью PHPStan можно было проверять шаблоны так же легко, как и другие PHP-файлы.

Мы работаем над этим, и вы увидите это в одной из следующих версий Latte.