Latte: jak na typový systém?

před 5 lety od David Grudl  

Typový systém. Klíčová záležitost pro vývoj robustních aplikací, ve které získalo PHP velký náskok před dynamickými jazyky jako je Python, Ruby nebo JavaScript. Framework Nette od počátku programátory k typovému a striktnímu programování vede. Latte 2.7 přineslo podporou typů i do šablon.

Díky tomu, že víme, jaký datový či objektový typ je v každé proměnné, může

  • IDE správně našeptávat
  • statická analýza odhalit chyby

Dva body, které zásadním způsobem zvyšují kvalitu a pohodlí vývoje.

Jak deklarovat typy na straně PHP?

Data budeme do šablony předávat jako objekt třídy, která definuje všech proměnné a jejich typy. S využitím nových vlastností PHP 7.4 by mohla vypadat třeba takto:

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

Použití:

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

Doplnění: díky novým vlastnostem PHP 8 lze příklad zapsat ještě zajímavěji takto:

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,
));

Jak deklarovat typy v šabloně?

Uvedenou třídu můžeme nyní spojit se šablonou. Stačí uvést na začátek:

{templateType MailTemplate}

A tím jsme definovali, že v šabloně bude čtveřice proměnných $lang, $address, $subject a $price včetně příslušných typů.

Alternativou je definovat typy jednotlivých proměnných přímo v šabloně, tj. bez vytváření třídy. K tomu slouží značka {varType}:

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

Samozřejmě lze kombinovat obojí. Vytvořit třídu, protože tím zajistíme našeptávání na straně presenteru, propojit ji se šablonou pomocí {templateType} a pro ostatní lokální proměnné v blocích apod. používat {varType}. Které můžeme chápat jako obdobu /** @var type $variable */, což je komentář, kterým občas v PHP kódu instruujeme IDE nebo statický analyzér.

Nově lze typ uvést také ve značkách {var}, {default} nebo {define}:

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

Poznámka: z historických důvodů bylo možné ve značkách {var} a {default} psát proměnné i bez úvodního dolaru (a šipkou místo rovnítka). Protože to vytváří nejednoznačnost, zda jde o typ nebo proměnnou, je tato syntaxe zapovězená a Latte vás bude při jejím použití varovat. Jednoduchý způsob jak prohledat své šablony, jestli tam tento starý zápis nemáte, je hledat regulární výrazy /\{(var|default) [^$]/ a /\{(var|default) [^}]*=>/.

Jak si ušetřit práci?

Jak co nejsnáze napsat třídu šablony nebo značky {varType}? Nechte si je vygenerovat. Právě od toho existuje dvojice značek {templatePrint} a {varPrint}.

Pokud některou z těchto značek umístíte do šablony, místo běžného vykreslení se zobrazí návrh kódu třídy resp. seznam značek {varPrint}. Kód pak stačí jedním kliknutím označit a zkopírovat do projektu.

Součástí nette/application 3.1 (v beta verzi) je přetížená značka {templatePrint}, která generuje kód lépe uzpůsobený pro presentery.

Značka {varPrint} vypisuje lokální proměnné, které nejsou parametry šablony. Pokud chcete vypsat všechny proměnné, použijte {varPrint all}.

Našeptávání v IDE

Nejnovější verze Latte pluginu pro PhpStorm umí využít výše uvedených značek a poté napovídat na základě typů. Plugin zároveň zná typy standardních proměnných jako je třeba $user, $presenter, $basePath atd.

Viz také rozhovor s Matoušem o novinkách v pluginech pro PhpStorm.

Statická analýza

Cílem je, aby se daly všechny deklarované typy použít také pro statickou analýzu. Aby například pomocí PHPStan bylo možné kontrolovat šablony stejně snadno, jako jiné PHP soubory.

Na tomhle pracujeme a dočkáte se v některé z příštích verzí Latte.

Komentáře

  1. Rychlá kontrola {var} a {default} z CLI:

    grep -rE --include '*.latte' '\{(var|default) ([^$]|[^}]*=>)'
    před 5 lety
  2. Doplnění typů do maker {var} apod. je super. Stálo by za zmínku, že umí obě nullable syntaxe: ?int i int|null.

    před 4 lety
  3. Funguje i něco takového {varType TranslatorModule\Data\Task[] $tasks} nebo jak se zapisují pole objektů?

    před 4 lety
  4. Zdravím, půjde někdy něco takovéhoto?
    `{varType array<int,Libs\Menu\MenuItem> $menuList}`
    nebo
    `{var array<int,string> $menuItems = $menu->getMenuItems()}`

    jde o to určit typy hodnot v poli

    před 3 lety

Chcete-li odeslat komentář, přihlaste se