Boilerplate für PHP-Teams automatisieren
PHP-Teams schreiben täglich dieselben Boilerplate-Muster: ViewModels mit Constructor Property Promotion, Service-Interfaces mit Repository-Konventionen, PHPDoc-Blöcke für Magento-Klassen. Live Templates und Postfix Templates in PhpStorm reduzieren diese repetitiven Schreibaufgaben auf wenige Tastendrücke – und können als Team-Bibliothek geteilt werden.
Inhaltsverzeichnis
- 1. Live Templates vs. Postfix Templates: Unterschiede verstehen
- 2. Eigene Live Templates erstellen: Variablen und Tabstops
- 3. PHP 8.4 Boilerplate: Constructor Promotion und Enums
- 4. Magento-Templates: ViewModels, Plugins und Repositories
- 5. Postfix Templates: Ketten-Shortcuts im Alltag
- 6. Team-Bibliotheken exportieren und teilen
- 7. Hyvä-Templates: Alpine.js und Tailwind-Snippets
- 8. Live Templates im Vergleich: Wann was einsetzen
- 9. Zusammenfassung
- 10. FAQ
1. Live Templates vs. Postfix Templates: Unterschiede verstehen
Live Templates sind Textbausteine, die über ein Kürzel aktiviert werden. Man tippt das Kürzel, drückt Tab, und PhpStorm ersetzt es durch den vollständigen Template-Text. Der Cursor springt automatisch zu den definierten Tabstops, wo die variablen Teile eingetippt werden. Mit weiteren Tab-Drücken bewegt sich der Cursor zum nächsten Tabstop. Live Templates eignen sich für Muster, die man mit leerer Eingabe beginnt – ein neues Klassen-Gerüst, ein PHPDoc-Block oder eine if-Konstruktion.
Postfix Templates funktionieren umgekehrt: Man schreibt zuerst einen Ausdruck und hängt dann das Kürzel per Punkt an. Aus $collection.foreach wird eine komplette foreach-Schleife, in der $collection bereits als Iterator eingesetzt ist. Aus $value.notnull wird ein Null-Check. Postfix Templates sind besonders wertvoll, wenn man einen bereits getippten Ausdruck in eine Kontrollstruktur einwickeln möchte, ohne zurücknavigieren und umschreiben zu müssen. PhpStorm kommt mit einer umfangreichen Standardbibliothek für PHP, die durch eigene Templates erweitert werden kann.
2. Eigene Live Templates erstellen: Variablen und Tabstops
Unter Settings → Editor → Live Templates legt man neue Gruppen und Templates an. Jedes Template hat ein Kürzel (Abbreviation), einen Beschreibungstext und den Template-Text. Im Template-Text markieren $VARIABLENNAME$-Ausdrücke die Tabstops. Die Variable $END$ ist reserviert und gibt an, wo der Cursor nach dem letzten Tab-Schritt landen soll. Für Tabstops ohne Variable reicht ein einzelnes $END$.
Variablen können mit Expressions vorbelegt werden: fileNameWithoutExtension() liefert den Dateinamen ohne Endung, phpClassName() den Klassennamen aus dem Dateinamen, date("yyyy-MM-dd") das aktuelle Datum. Das Skip if defined-Flag verhindert, dass der Cursor eine Variable überspringt, die durch eine Expression bereits einen Wert hat. Der Kontextbereich (Applicable In) bestimmt, in welchen Dateitypen und Bereichen (Klasse, Statement, Expression, Comment) das Template aktivierbar ist.
<?php
/**
* Live Template Kürzel: vmclass
* Applicable: PHP → Class
* Beschreibung: Magento ViewModel Klasse mit Constructor Property Promotion
*
* Template-Text:
* ---------------------------------------------------------------
* declare(strict_types=1);
*
* namespace $NAMESPACE$;
*
* use Magento\Framework\View\Element\Block\ArgumentInterface;
*
* /**
* * $CLASSNAME$ ViewModel
* *
* * @package $NAMESPACE$
* * /
* class $CLASSNAME$ implements ArgumentInterface
* {
* public function __construct(
* $END$
* ) {
* }
* }
* ---------------------------------------------------------------
* Variablen:
* $NAMESPACE$ → Expression: phpNamespace() | Skip if defined: nein
* $CLASSNAME$ → Expression: phpClassName() | Skip if defined: ja
* $END$ → reserviert (Cursor-Endposition)
*/
// Ergebnis nach Expansion von "vmclass" + Tab:
declare(strict_types=1);
namespace Mironsoft\Catalog\ViewModel;
use Magento\Framework\View\Element\Block\ArgumentInterface;
/**
* ProductList ViewModel
*
* @package Mironsoft\Catalog\ViewModel
*/
class ProductList implements ArgumentInterface
{
public function __construct(
// Cursor landet hier
) {
}
}
3. PHP 8.4 Boilerplate: Constructor Promotion und Enums
PHP 8.4 bringt Property Hooks, readonly-Klassen und asymmetrische Sichtbarkeit. Für Teams, die auf PHP 8.4 umstellen, lohnt es sich, Live Templates für die häufigsten neuen Muster zu erstellen. Ein Template für eine readonly-Klasse mit Constructor Property Promotion reduziert das Aufschreiben dieser Struktur von etwa 20 Zeilen auf einen Tab-Expand. Enum-Templates mit from()- und tryFrom()-Methoden decken einen weiteren häufigen Boilerplate-Fall ab.
Besonders nützlich ist ein Template für PHPDoc-Blöcke mit @param-Zeilen, die durch eine Expression automatisch auf den Methodennamen vorbelegt werden. PhpStorm generiert zwar PHPDoc automatisch beim Tippen von /** über einer Methode, aber für Klassen-Level-Kommentare mit spezifischen Tags (@since, @api) oder für Interfaces mit vollständiger Dokumentation sind eigene Templates deutlich schneller. Ein weiteres nützliches Template: declare(strict_types=1); als erstes Statement – das Kürzel dstrict expandiert in zwei Zeilen und setzt den Cursor danach, was bei jedem neuen PHP-File spart.
<?php
// Live Template Kürzel: enumbs (Backed String Enum mit Labels)
// Applicable: PHP → File
declare(strict_types=1);
namespace Mironsoft\Catalog\Enum;
/**
* OrderStatus backed enum
*
* Provides type-safe order status with display labels.
*/
enum OrderStatus: string
{
case Pending = 'pending';
case Processing = 'processing';
case Complete = 'complete';
case Canceled = 'canceled';
/**
* Return human-readable label for the status.
*/
public function label(): string
{
return match($this) {
self::Pending => 'Ausstehend',
self::Processing => 'In Bearbeitung',
self::Complete => 'Abgeschlossen',
self::Canceled => 'Storniert',
};
}
/**
* Return all statuses as associative array for select fields.
*
* @return array<string, string>
*/
public static function toSelectOptions(): array
{
return array_column(
array_map(
fn(self $case) => ['value' => $case->value, 'label' => $case->label()],
self::cases()
),
'label',
'value'
);
}
}
4. Magento-Templates: ViewModels, Plugins und Repositories
Magento 2 hat wiederkehrende Muster, die sich hervorragend als Live Templates abbilden lassen. Ein Plugin-Template (Kürzel: mgplugin) erzeugt das Gerüst einer Interceptor-Klasse mit aroundMethodName- und afterMethodName-Methoden, die korrekte callable $proceed-Parameter enthalten. Ein Repository-Template (Kürzel: mgrepo) erzeugt eine Repository-Klasse mit getById, save, delete und getList-Methoden, die das jeweilige Model-Interface als Rückgabetyp verwenden.
Für die häufige Kombination aus di.xml-Eintrag und der zugehörigen PHP-Klasse reicht ein Live Template leider nicht – dafür eignen sich PhpStorm File Templates besser. Aber für reine PHP-Boilerplate sind Live Templates die schnellste Lösung. Ein ViewModel-Template mit vorkonfiguriertem ArgumentInterface und Constructor Property Promotion ist nach einmaliger Einrichtung für alle Projektmitglieder sofort verfügbar, sobald die Template-Bibliothek per Settings-Export geteilt wird.
<?php
// Live Template Kürzel: mgplugin
// Erzeugt ein Magento-Plugin-Grundgerüst
declare(strict_types=1);
namespace Mironsoft\Catalog\Plugin;
use Magento\Catalog\Model\Product;
/**
* ProductPlugin intercepts product-related methods.
*
* Register in etc/di.xml:
* <type name="Magento\Catalog\Model\Product">
* <plugin name="mironsoft_catalog_product_plugin"
* type="Mironsoft\Catalog\Plugin\ProductPlugin" />
* </type>
*/
class ProductPlugin
{
public function __construct(
private readonly \Psr\Log\LoggerInterface $logger,
) {
}
/**
* After plugin: called after Product::getName().
*
* @param Product $subject The original product instance
* @param string $result The original return value
* @return string The modified return value
*/
public function afterGetName(Product $subject, string $result): string
{
// Modify result or add side effects here
return $result;
}
/**
* Around plugin: wraps Product::isSalable() with custom logic.
*
* @param Product $subject The original product instance
* @param callable $proceed Call $proceed() to invoke the original method
* @return bool
*/
public function aroundIsSalable(Product $subject, callable $proceed): bool
{
// Custom pre-logic
$result = $proceed();
// Custom post-logic
return $result;
}
}
5. Postfix Templates: Ketten-Shortcuts im Alltag
PhpStorm liefert standardmäßig eine Reihe nützlicher Postfix Templates für PHP: .var wickelt einen Ausdruck in eine $variable = ...-Zuweisung ein, .not negiert einen booleschen Ausdruck, .return macht aus dem Ausdruck eine return-Anweisung, .null erzeugt einen === null-Check. Diese Shortcuts sind besonders effizient, wenn man einen Ausdruck während des Tippens in eine Kontrollstruktur umwandeln möchte, ohne zurückzunavigieren.
Eigene Postfix Templates lassen sich unter Settings → Editor → General → Postfix Completion anlegen. Ein nützliches Custom Template für Magento: .escHtml wickelt einen Ausdruck in $block->escapeHtml($EXPR$) ein. Ein weiteres: .logger erzeugt $this->logger->info($EXPR$). Diese Templates sparen mehrere Cursor-Bewegungen bei jedem Einsatz und stellen gleichzeitig sicher, dass keine unsicheren String-Ausgaben ohne Escaping landen – ein häufiger Sicherheitsfehler in Magento-Templates.
6. Team-Bibliotheken exportieren und teilen
PhpStorm speichert Live Templates in XML-Dateien im Konfigurationsverzeichnis, das je nach Betriebssystem unterschiedlich liegt (unter Linux: ~/.config/JetBrains/PhpStorm[version]/templates/). Für Teams empfiehlt sich der Export über File → Manage IDE Settings → Export Settings mit ausgewähltem Live Templates-Checkbox. Die exportierte ZIP-Datei kann ins Projekt-Repository eingecheckt werden (.idea/templates/ oder ein eigener dev/phpstorm/-Ordner), sodass neue Teammitglieder die Bibliothek sofort importieren können.
Alternativ bietet PhpStorm die Settings Sync-Funktion, die Templates über ein JetBrains-Konto auf allen Geräten synchronisiert. Für Teams mit mehreren Entwicklern ist das praktisch, solange alle denselben Account nutzen dürfen – was in professionellen Umgebungen oft nicht der Fall ist. Der manuelle XML-Export in das Git-Repository ist daher die empfohlene Methode für professionelle PHP-Teams: versioniert, nachvollziehbar und unabhängig von externen Diensten.
7. Hyvä-Templates: Alpine.js und Tailwind-Snippets
Für Hyvä-Projekte mit .phtml-Templates lohnen sich Live Templates für die häufigsten Alpine.js-Muster. Ein Template (Kürzel: axdata) erzeugt ein x-data-Attribut mit einer leeren JavaScript-Objekt-Expression und einem x-init-Aufruf. Ein weiteres (Kürzel: axcomponent) erzeugt die vollständige Alpine.js-Komponenten-Registrierung mit document.addEventListener('alpine:init')-Wrapper und Alpine.data()-Aufruf – inklusive dem notwendigen $hyvaCsp->registerInlineScript()-Aufruf, der in Hyvä für CSP-Konformität zwingend ist.
Tailwind-Klassen-Kombinationen, die im Projekt häufig vorkommen, können ebenfalls als Live Templates gespeichert werden. Statt jedes Mal die vollständige Button-Klassen-Kombination zu tippen (inline-flex items-center justify-center gap-2 rounded-xl font-semibold transition-colors bg-fuchsia-600 text-white hover:bg-fuchsia-700), reicht das Kürzel btnprimary. Das ist besonders in Templates nützlich, wo CSS-Klassen nicht aus Komponenten-Bibliotheken importiert werden, sondern direkt im Markup stehen.
<?php
// Live Template Kürzel: hyvacomponent
// Applicable: HTML → in script-Tag-Bereich
// Erzeugt vollständige Hyvä/Alpine.js-Komponenten-Registrierung
/** @var \Hyva\Theme\Model\ViewModelRegistry $viewModels */
/** @var \Hyva\Theme\ViewModel\HyvaCsp $hyvaCsp */
?>
<script>
// Alpine.js component registration for Hyvä Theme
// Registered via alpine:init event to ensure Alpine is ready
document.addEventListener('alpine:init', () => {
Alpine.data('productTabs', () => ({
activeTab: 'description',
init() {
// Initialization logic here
},
switchTab(tabName) {
this.activeTab = tabName;
},
isActive(tabName) {
return this.activeTab === tabName;
},
}));
});
</script>
<?= /* @noEscape */ $hyvaCsp->registerInlineScript() ?>
<!-- Usage in template -->
<div x-data="productTabs()" class="mt-8">
<nav class="flex gap-2 border-b border-slate-200 mb-6">
<button @click="switchTab('description')"
:class="isActive('description') ? 'border-b-2 border-fuchsia-600 text-fuchsia-700' : 'text-slate-600'"
class="px-4 py-2 font-semibold text-sm transition-colors">
<?= $block->escapeHtml(__('Beschreibung')) ?>
</button>
<button @click="switchTab('attributes')"
:class="isActive('attributes') ? 'border-b-2 border-fuchsia-600 text-fuchsia-700' : 'text-slate-600'"
class="px-4 py-2 font-semibold text-sm transition-colors">
<?= $block->escapeHtml(__('Eigenschaften')) ?>
</button>
</nav>
<div x-show="isActive('description')" x-transition>
<?= $block->getChildHtml('description') ?>
</div>
<div x-show="isActive('attributes')" x-transition>
<?= $block->getChildHtml('additional') ?>
</div>
</div>
8. Live Templates im Vergleich: Wann was einsetzen
Die Abgrenzung zwischen Live Templates, Postfix Templates, File Templates und Code Generation in PhpStorm ist nicht immer intuitiv. Die folgende Übersicht hilft bei der Entscheidung, welches Werkzeug für welchen Anwendungsfall geeignet ist.
| Werkzeug | Auslöser | Stärke | Typischer Einsatz |
|---|---|---|---|
| Live Templates | Kürzel + Tab | Mehrzeiliger Boilerplate | Neue Klassen, Methoden, PHPDoc |
| Postfix Templates | Ausdruck + .kürzel | Ausdruck einwickeln | return, null-Check, foreach, var |
| File Templates | Neue Datei | Komplettes Datei-Gerüst | Neue PHP-Klasse mit Namespace |
| Code Generation | Alt+Insert | Getter/Setter, Override | Methoden aus Interface generieren |
| Surround With | Auswahl + Ctrl+Alt+T | Selektion einwickeln | try/catch, if, while um Code |
Ein häufiger Fehler beim Einsatz von Live Templates: zu breite Kontextkonfiguration. Wenn ein Template für alle PHP-Kontexte aktiv ist, erscheint das Kürzel als Autocomplete-Vorschlag in unpassenden Situationen – zum Beispiel innerhalb von Strings oder Kommentaren. Immer den engsten passenden Kontext wählen: PHP → Statement für Statements, PHP → Class Member für Methoden und Properties. Das verbessert die Signal-Rausch-Ratio in der Autocomplete-Liste erheblich.
Mironsoft
Magento 2, Hyvä Themes und PHP 8.4 Entwicklung
PHP-Boilerplate für euer Team automatisieren?
Wir erstellen projekt-spezifische Live Template Bibliotheken für Magento 2, Hyvä Themes und PHP 8.4 und integrieren sie in euren Team-Workflow – mit Versionierung und Import-Anleitung.
Template-Bibliothek
Live Templates für ViewModels, Plugins, Repositories und Hyvä-Komponenten
Team-Export
XML-Export ins Git-Repository mit Import-Dokumentation für neue Entwickler
PHP 8.4 Patterns
Property Hooks, readonly-Klassen und asymmetrische Sichtbarkeit als Snippets
9. Zusammenfassung
Live Templates und Postfix Templates in PhpStorm sind eines der am meisten unterschätzten Produktivitätswerkzeuge für PHP-Teams. Einmal eingerichtet, reduzieren sie das Schreiben von Boilerplate-Code erheblich – ohne dass Entwickler die IDE wechseln, externe Snippet-Tools einrichten oder Code kopieren müssen. Die Template-Bibliothek wächst mit dem Projekt: Jedes neue wiederkehrende Muster, das mehr als dreimal getippt wird, ist ein Kandidat für ein Live Template.
Für Magento 2 Teams mit Hyvä Themes und PHP 8.4 sind die häufigsten Kandidaten: ViewModel-Klassen, Plugins, Repositories, PHPDoc-Blöcke mit Magento-spezifischen Tags, Alpine.js-Komponenten-Registrierungen und Tailwind-Klassen-Kombinationen für Hyvä-Templates. Der Team-Export über Git stellt sicher, dass alle Entwickler denselben Standard-Boilerplate verwenden und neu hinzukommende Kollegen sofort produktiv sind.
Live Templates in PhpStorm — Das Wichtigste auf einen Blick
Live Templates
Kürzel + Tab für mehrzeiligen Boilerplate. Variablen mit Expressions vorbelegen (phpClassName, fileNameWithoutExtension, date). Kontext eng konfigurieren.
Postfix Templates
Ausdruck + .kürzel um Kontrollstrukturen einwickeln: .return, .null, .foreach, .var. Eigene Custom Templates in Settings → General → Postfix Completion.
Team-Sharing
XML-Export ins Git-Repository (~/.config/JetBrains/PhpStorm*/templates/). File → Manage IDE Settings → Export Settings → Live Templates auswählen.
Hyvä & Magento
Templates für ViewModels, Plugins, Alpine.js-Komponenten und $hyvaCsp->registerInlineScript()-Aufrufe. escHtml-Postfix für sichere Template-Ausgaben.