Coding Standard: Konventionen, die Wartung sparen
Namensgebung, Einrückung, Dateiaufbau und Kommentare als prüfbare Regeln statt als Geschmacksfrage – mit den Werkzeugen, die den Standard automatisch durchsetzen.
Das Wichtigste
- Ein Standard wirkt nur, wenn ein Werkzeug ihn prüft. Eine Regel im Wiki, die niemand misst, wird nach drei Monaten ignoriert.
- PSR-12 ist der De-facto-Standard für PHP. Die Diskussion, ob Klammern in derselben Zeile stehen, ist damit erledigt.
- PHP-CS-Fixer korrigiert automatisch, PHPStan findet Fehler. Beides gehört in die Continuous Integration, nicht in die Code-Review.
- Bei Bestandscode nie alles auf einmal formatieren: ein Commit mit 4.000 geänderten Dateien macht die Versionsgeschichte unbrauchbar.
Ein Coding Standard ist keine Stilfrage, sondern eine Massnahme zur Fehlerreduktion. Einheitlich formatierter Code lässt sich schneller lesen, Änderungen sind in der Versionsgeschichte klarer zu erkennen, und der Diff zeigt nur, was sich fachlich geändert hat.
Was ein Standard regeln sollte
| Bereich | typische Festlegung |
|---|---|
| Einrückung | vier Leerzeichen, keine Tabulatoren |
| Zeilenlänge | Richtwert 120 Zeichen, kein hartes Limit |
| Klassennamen | PascalCase |
| Methoden und Variablen | camelCase |
| Konstanten | SCREAMING_SNAKE_CASE |
| Dateiaufbau | eine Klasse pro Datei, Dateiname gleich Klassenname |
| Namensräume | PSR-4, Verzeichnis spiegelt Namensraum |
| Zeilenende | LF, nie CRLF |
| Kodierung | UTF-8 ohne BOM |
| Schlusstag | ?> in reinen PHP-Dateien weglassen |
Der letzte Punkt ist mehr als Kosmetik: Ein Leerzeichen nach dem Schlusstag wird ausgegeben und erzeugt “headers already sent” – ein Fehler, dessen Ursache man ohne diesen Hinweis lange sucht.
Nimm PSR-12
PSR-12 ist der breit akzeptierte Standard im PHP-Umfeld. Die Vorteile eines fertigen Standards gegenüber einem eigenen:
- Er ist bereits ausdiskutiert. Niemand streitet mehr über die Position der geschweiften Klammer.
- Alle Werkzeuge kennen ihn ab Werk.
- Neue Teammitglieder bringen ihn mit.
- Fremde Bibliotheken sehen aus wie eigener Code.
Ein projektspezifischer Zusatz ist trotzdem sinnvoll – etwa: strikte Typen in jeder Datei, keine Klassen ohne Rückgabetyp, keine else nach einem return.
Durchsetzung mit Werkzeugen
PHP-CS-Fixer korrigiert die Form automatisch:
<?php
// .php-cs-fixer.dist.php
return (new PhpCsFixer\Config())
->setRiskyAllowed(true)
->setRules([
'@PSR12' => true,
'declare_strict_types' => true,
'ordered_imports' => ['sort_algorithm' => 'alpha'],
'no_unused_imports' => true,
'array_syntax' => ['syntax' => 'short'],
'trailing_comma_in_multiline' => true,
'single_quote' => true,
])
->setFinder(
PhpCsFixer\Finder::create()->in(__DIR__ . '/src')
);
# nur prüfen, nichts ändern - für die CI
vendor/bin/php-cs-fixer fix --dry-run --diff
# korrigieren - lokal vor dem Commit
vendor/bin/php-cs-fixer fix
PHPStan prüft die Bedeutung:
# phpstan.neon
parameters:
level: 6
paths:
- src
treatPhpDocTypesAsCertain: false
Level 0 bis 9, wobei 9 sehr streng ist. Für ein Bestandsprojekt beginnt man bei 0 oder 1, erzeugt eine Baseline für die vorhandenen Meldungen und erhöht das Level, sobald der aktuelle Stand sauber ist:
vendor/bin/phpstan analyse --generate-baseline
Die Baseline friert bestehende Meldungen ein, ohne sie zu ignorieren – neuer Code wird ab sofort streng geprüft, alter kann nach und nach nachgezogen werden.
Einführung in einem gewachsenen Projekt
Der Fehler, den man einmal macht: das gesamte Projekt in einem Commit umformatieren. Danach zeigt git blame für jede Zeile diesen Commit, und die Frage “warum steht das so da” lässt sich nicht mehr beantworten.
Der bessere Weg:
-
Konfiguration anlegen und einchecken, noch nichts ändern.
-
In der CI nur die im Branch geänderten Dateien prüfen:
git diff --name-only --diff-filter=ACM origin/main... -- '*.php' \ | xargs -r vendor/bin/php-cs-fixer fix --dry-run --diff --path-mode=intersection -
Dateien, die aus anderen Gründen angefasst werden, dabei mit formatieren – in einem eigenen Commit, getrennt von der fachlichen Änderung.
-
Wenn irgendwann fast alles konform ist, den Rest in einem klar benannten Commit nachziehen und diesen in
.git-blame-ignore-revseintragen:git config blame.ignoreRevsFile .git-blame-ignore-revs
Damit überspringt git blame den reinen Formatierungscommit.
Kommentare: weniger und besser
Kommentare, die beschreiben, was der Code tut, veralten und lügen irgendwann. Wertvoll sind die, die erklären, warum etwas so ist:
// Schlecht - wiederholt nur den Code
// Zähler um eins erhöhen
$i++;
// Gut - erklärt eine Entscheidung, die man sonst rückgängig machen würde
// Die API des Anbieters begrenzt auf 60 Anfragen pro Minute; ohne diese
// Pause liefert sie ab der 61. Anfrage HTTP 429 und sperrt für 15 Minuten.
usleep(1_000_000);
Für Signaturen leisten Typdeklarationen mehr als jeder Kommentar. Ein @param string $name über einer Methode mit string $name ist Redundanz, die irgendwann auseinanderläuft. PHPDoc bleibt sinnvoll für Dinge, die das Typsystem nicht ausdrückt – etwa die Form eines Arrays:
/** @param list<array{name: string, preis: float}> $produkte */
public function berechneSumme(array $produkte): float
PHPStan wertet solche Angaben aus und prüft sie – damit ist der Kommentar nicht mehr nur Dokumentation, sondern eine geprüfte Zusage.
Häufige Fragen
Welchen Standard soll ich nehmen?
PSR-12, ergänzt um die Regeln, die euer Projekt tatsächlich braucht. Ein eigener Standard kostet Diskussionszeit und bringt gegenüber PSR-12 keinen messbaren Vorteil – ausser dass neue Teammitglieder ihn erst lernen müssen.
Wie führe ich einen Standard in einem alten Projekt ein?
Schrittweise. Zuerst die Konfiguration anlegen und in der CI nur neue oder geänderte Dateien prüfen. Wer das ganze Projekt in einem Commit umformatiert, verliert die Nachvollziehbarkeit über git blame für jede einzelne Zeile.
Was ist der Unterschied zwischen PHP-CS-Fixer und PHPStan?
PHP-CS-Fixer arbeitet an der Form: Einrückung, Reihenfolge, Leerzeichen – und korrigiert selbstständig. PHPStan analysiert die Bedeutung und findet Typfehler, unerreichbaren Code und Aufrufe, die zur Laufzeit scheitern würden. Beide ergänzen sich, keines ersetzt das andere.
Braucht ein Ein-Personen-Projekt einen Standard?
Spätestens beim Wiedereinstieg nach sechs Monaten ja. Der Aufwand ist eine Konfigurationsdatei und ein Kommando, der Gewinn ist Code, der sich nach der Pause noch lesen lässt.
Weiterlesen
- Template-Engines in PHP: Übersicht
Was eine Engine gegenüber purem PHP bringt, welche Ansätze es gibt und wie du für ein Projekt entscheidest.
- Von XHTML zu semantischem HTML
Was aus den strengen XHTML-Regeln übrig geblieben ist, welche Elemente heute Struktur tragen und warum Semantik Barrierefreiheit ist.
- vlibTemplate: Aufbau, Syntax und Beispiele
Platzhalter, Schleifen, Bedingungen und Includes der klassischen Engine - inklusive Hinweisen zum Betrieb auf aktuellen PHP-Versionen.
- Smarty: Grundlagen und typische Muster
Zuweisungen, Modifier, Blöcke und Caching - und wo Smarty in modernen Projekten noch seinen Platz hat.