68 lines
4.6 KiB
Markdown
68 lines
4.6 KiB
Markdown
# PHP & Symfony Engineering Guidelines
|
|
|
|
## 1. Core PHP Standard
|
|
Wir schreiben modernen, typensicheren und expliziten Code. Ziel ist es, Fehler zur Compile-Zeit bzw. via statischer Analyse zu finden.
|
|
|
|
* **Strict Typing:** Jede Datei beginnt zwingend mit `declare(strict_types=1);`.
|
|
* **Typisierung:**
|
|
* Konsequentes Type Hinting für alle Parameter und Rückgabewerte (inkl. `void`).
|
|
* Nutzung von Union- und Intersection Types.
|
|
* `mixed` ist verboten, außer in absolut unvermeidbaren Generics.
|
|
* **Modern Features (PHP 8.2+):**
|
|
* **Readonly:** Standard für DTOs, Value Objects und Services (`readonly class`).
|
|
* **Constructor Promotion:** Nutzung zur Reduktion von Boilerplate.
|
|
* **Enums:** Einsatz anstelle von Konstanten oder Strings für feste Zustände.
|
|
* **Match Expression:** Bevorzugt gegenüber `switch`.
|
|
* **Anti-Magic:** Magic Methods (`__call`, `__get` etc.) und dynamische Properties sind **strikt verboten**.
|
|
|
|
## 2. Control Flow & Readability
|
|
Lesbarkeit schlägt akademische Perfektion. Code muss für andere Senioren ohne "Rätselraten" sofort verstehbar sein.
|
|
|
|
* **Control Flow:** Nutzung von **Early Returns** und **Guard Clauses**. Verschachtelte `if-else`-Strukturen sind zu vermeiden, um die kognitive Last gering zu halten.
|
|
* **Self-Explaining Code:** Namen müssen den Intent beschreiben (`calculateTotalTax()` statt `calc()`). Booleans beginnen mit `is`, `has` oder `can`.
|
|
* **Kommentare:** Kommentare werden nur eingesetzt, wenn:
|
|
1. Der Code aufgrund einer Sonderlösung **nicht selbsterklärend** ist (Dokumentation des "Warum").
|
|
2. **Arrays/Collections typisiert** werden müssen (`/** @var UserDTO[] $users */`), sofern PHPStan dies nicht anders erfassen kann.
|
|
|
|
## 3. Data Structures & Collections
|
|
Wir vermeiden "Mystery Meat"-Datenstrukturen zugunsten von Typsicherheit.
|
|
|
|
* **No Associative Arrays:** Die Nutzung von assoziativen Arrays als Pseudo-Objekte/Datencontainer ist verboten. Es werden immer **dedizierte Objekte (DTOs)** verwendet.
|
|
* **Collections:**
|
|
* **Transport:** Für einfache Listen, die nur durchiteriert werden, reichen typisierte Arrays (`array<T>`).
|
|
* **Domain-Logik:** Sobald eine Liste fachliche Logik besitzt (z.B. Filterung, Aggregation), wird eine dedizierte **Collection-Klasse** erstellt (implementiert `IteratorAggregate` und `Countable`).
|
|
|
|
## 4. Infrastructure & Symfony Implementation
|
|
Symfony ist der Adapter zur Außenwelt, nicht das Zentrum der Applikation.
|
|
|
|
* **Dependency Injection:** Ausschließlich **Constructor Injection**. Kein Service-Locator (`$this->container->get()`). DI erfolgt primär gegen Interfaces (Ports).
|
|
* **Controller:** "Thin Controller". Aufgaben sind: Request-Daten validieren/extrahieren $\rightarrow$ Application-Service aufrufen $\rightarrow$ Response transformieren. Keine Business-Logik im Controller.
|
|
* **Third-Party SDKs:** Alle externen Services/SDKs werden konsequent hinter einem **eigenen Interface (Port)** in der Infrastructure-Schicht gekapselt. Vendor-Klassen dürfen niemals den Application- oder Domain-Layer erreichen.
|
|
|
|
## 5. Persistence & Entity Design
|
|
Wir minimieren die Koppelung an das ORM, um Performance und Testbarkeit zu sichern.
|
|
|
|
* **Simple Entities:** Entitäten werden flach gehalten.
|
|
* **Avoid Joins:** Gejointe Entitäten (komplexe `@ManyToOne` / `@OneToMany`) sind grundsätzlich zu vermeiden. Referenzen erfolgen über **IDs**. Die Zusammenführung erfolgt explizit in den Repositories/Services.
|
|
* **Mapping:** Transformationen zwischen Infrastructure-Entities und Domain-Modellen erfolgen ausschließlich über dedizierte **Mapper-Klassen in der Dataschicht**.
|
|
|
|
## 6. Validation Pipeline (Shift-Left)
|
|
Fehler werden so früh wie möglich abgefangen:
|
|
`Request` $\rightarrow$ `DTO Asserts/Validation` $\rightarrow$ `Application Logic` $\rightarrow$ `Domain Complex Tests`.
|
|
|
|
## 7. Quality Gates & Workflow (Definition of Done)
|
|
Bevor Code in ein Review geht, müssen folgende lokale Checks erfolgreich durchlaufen sein:
|
|
|
|
1. **Syntax Check:** `php -l`
|
|
2. **Statische Analyse:** `phpstan analyse` (Ziel Level 8/9). *Pragmatismus-Regel:* Wenn Typisierung die Lesbarkeit massiv zerstört $\rightarrow$ Review-Dialog statt "Force-Typing".
|
|
3. **Automatisierte Tests:** `phpunit` (Unit, Integration, Functional).
|
|
|
|
---
|
|
|
|
### Die Golden Rules im Überblick:
|
|
1. **Kein Framework / Keine Vendor-Klassen im Domain.**
|
|
2. **Flache Entitäten / Referenzen über IDs.**
|
|
3. **Immutability by Default (`readonly`).**
|
|
4. **Keine assoziativen Arrays $\rightarrow$ Dedizierte Objekte.**
|
|
5. **Early Returns $\rightarrow$ Flacher Code.**
|
|
6. **Local Check: `php -l` $\rightarrow$ `phpstan` $\rightarrow$ `phpunit`.** |