phtml-Templates schreiben: Escaper, Best Practices, keine rohen Ausgaben ohne Escaping
phtml-Templates schreiben: Escaper, Best Practices, keine rohen Ausgaben ohne Escaping
~7 Min. Lesezeit Zuletzt aktualisiert am 9. August 2026
Ein .phtml-Template in Hyvä sieht auf den ersten Blick wie ganz normales PHP-in-HTML aus - und das ist es größtenteils auch. Der wichtigste Unterschied zu "schnell mal ein bisschen PHP in HTML mischen" ist die konsequente Nutzung des Escapers für jede dynamische Ausgabe.
Der Escaper: $escaper
Jedes Standard-Template bekommt eine Instanz von \Magento\Framework\Escaper als $escaper zur Verfügung gestellt. Die wichtigsten Methoden:
escapeHtml($string)- für normalen Text-Inhalt (Standard-Fall, am häufigsten gebraucht).escapeHtmlAttr($string)- für Werte innerhalb von HTML-Attributen, z. B.altodertitle.escapeUrl($string)- für URLs, z. B. inhrefodersrc.escapeJs($string)- für Werte, die innerhalb eines<script>-Blocks in JavaScript eingebettet werden.
<?php
/** @var \Magento\Framework\Escaper $escaper */
/** @var \Mironsoft\TeamPage\ViewModel\TeamMembers $teamViewModel */
?>
<?php foreach ($teamViewModel->getTeamMembers() as $member): ?>
<article>
<h3><?= $escaper->escapeHtml($member['name']) ?></h3>
<img src="<?= $escaper->escapeUrl($member['photo_url']) ?>"
alt="<?= $escaper->escapeHtmlAttr($member['name']) ?>">
</article>
<?php endforeach; ?>Achtung: Rohe Ausgaben wie <?= $member['name'] ?> ohne Escaper sind eine XSS-Sicherheitslücke, sobald der Wert (auch nur teilweise) aus Nutzereingaben oder aus dem Admin stammt - und selbst bei scheinbar sicheren Werten ist es einfach die falsche Gewohnheit. In diesem Projekt gilt: jede dynamische Ausgabe geht durch den passenden Escaper, ausnahmslos.
@var-Annotationen am Dateianfang
Am Anfang jedes Templates stehen /** @var Type $variable */-Kommentare für $block, $escaper und jedes gebundene ViewModel. Das ist nicht nur Dokumentation - PhpStorm und PHPStan nutzen diese Annotationen für Autovervollständigung und statische Analyse, was in reinen .phtml-Dateien ohne echte Typdeklaration sonst nicht möglich wäre.
Logik im Template minimal halten
Ein Template sollte im Wesentlichen nur ausgeben, was ihm ein ViewModel oder ein Block liefert - Schleifen und einfache Bedingungen sind normal, komplexe Geschäftslogik gehört aber ins ViewModel, nicht ins Template. Eine gute Faustregel: Wenn eine Bedingung mehr als eine Zeile PHP-Ausdruck braucht, gehört sie wahrscheinlich als eigene Methode ins ViewModel.
<?php // Eher vermeiden: komplexe Logik direkt im Template
<?php if (count(array_filter($members, fn($m) => $m['category'] === 'design')) > 0): ?>
<?php // Besser: fertige, sprechende Methode im ViewModel
<?php if ($teamViewModel->hasDesignTeamMembers()): ?>Tailwind-Klassen lesbar halten
Bei vielen Utility-Klassen in einem Element lohnt es sich, das öffnende Tag über mehrere Zeilen zu formatieren statt eine sehr lange Zeile zu erzeugen - das hält den Diff bei künftigen Änderungen klein und die Klassen überschaubar. Kapitel 11-13 gehen im Detail auf Tailwind in Hyvä-Templates ein.