# Coding Guidelines ## Allgemeine Prinzipien Diese Guidelines definieren die Standards für die Entwicklung und Wartung des Projekts. Sie sorgen für Konsistenz, Lesbarkeit und Wartbarkeit des Codes. ## PHP-Version - **PHP 8.4**: Die Codebase nutzt stets die neueste stabile PHP-Version (aktuell PHP 8.4) - Alle neuen PHP-Sprachfeatures sollten, wo sinnvoll, genutzt werden ## Abhängigkeiten - **Externe Abhängigkeiten vermeiden**: Das Projekt soll möglichst ohne externe Bibliotheken auskommen - **Eigene Implementierungen bevorzugen**: Anstatt externe Pakete einzubinden, sollten eigene Lösungen entwickelt werden - **Erlaubte Abhängigkeiten**: Nur die bereits in composer.json definierten Pakete dürfen verwendet werden - **Neue Abhängigkeiten**: Müssen explizit genehmigt werden und sollten nur in Ausnahmefällen hinzugefügt werden ## Klassenstruktur ### Klassen - **Alle Klassen müssen `final` sein**, es sei denn, es gibt einen zwingenden Grund für Vererbung - **Keine abstrakten Klassen** - bevorzuge Interfaces und Kompositionen - **Klassen sollten `readonly` sein**, wann immer möglich - Interfaces verwenden, um Verträge zwischen Komponenten zu definieren ```php // Gut final readonly class AnalyticsManager { // ... } // Vermeiden abstract class BaseManager { // ... } ``` ### Properties - **Properties sollten `readonly` sein**, wann immer möglich - Private Visibility für alle Properties, es sei denn, es gibt einen zwingenden Grund - Typisierung ist obligatorisch für alle Properties ```php // Gut private readonly StorageInterface $storage; // Vermeiden public array $config; ``` ## Methoden und Funktionen - Typisierung ist obligatorisch für alle Parameter und Rückgabewerte - Methoden sollten klein und fokussiert sein (Single Responsibility) - Verwende named arguments für bessere Lesbarkeit ```php // Gut public function track(string $event, array $properties = [], ?string $userId = null): void { // ... } // Vermeiden public function process($data) { // ... } ``` ## Dependency Injection - Constructor Injection für alle Abhängigkeiten - Keine Service Locator oder globale Zustände - Verwende das `#[Initializer]`-Attribut für Service-Registrierung ```php // Gut public function __construct( private readonly Configuration $config, private readonly StorageInterface $storage ) {} // Vermeiden public function __construct() { $this->config = Container::get(Configuration::class); } ``` ## Moderne PHP-Features ### Nullable Types und Union Types ```php public function findUser(?int $id): ?User public function process(int|string $identifier): void ``` ### Match Expression statt Switch ```php // Gut return match($storageType) { 'file' => new FileStorage($path), 'redis' => new RedisStorage($connection), default => throw new \InvalidArgumentException("Nicht unterstützter Storage-Typ: {$storageType}") }; // Vermeiden switch ($storageType) { case 'file': return new FileStorage($path); // ... } ``` ### Named Arguments ```php $this->createUser( email: 'user@example.com', role: 'admin', sendWelcomeEmail: true ); ``` ### Constructor Property Promotion ```php public function __construct( private readonly Configuration $config, private readonly PathProvider $pathProvider ) {} ``` ## Fehlerbehandlung - Spezifische Exceptions werfen - Typed Exceptions verwenden - Early Return Pattern bevorzugen ```php // Gut if (!$this->isValid()) { throw new ValidationException('Ungültige Daten'); } // Vermeiden if ($this->isValid()) { // Lange Verarbeitung... } else { throw new Exception('Fehler'); } ``` ## Testing - Tests mit Pest-Framework schreiben - Für jede öffentliche Methode sollte mindestens ein Test existieren - Mocking nur für externe Abhängigkeiten verwenden ```php test('track method records events correctly', function () { $analytics = new Analytics($manager, $dispatcher); $analytics->track('test_event', ['key' => 'value']); expect($manager->getEvents())->toHaveCount(1); }); ``` ## Dokumentation - PHPDoc für alle öffentlichen Methoden und Klassen - Typen in PHPDoc sollten den tatsächlichen Typen entsprechen - Klare, beschreibende Kommentare für komplexe Logik ```php /** * Zeichnet ein Event auf und wendet Middleware an * * @param string $event Event-Name * @param array $properties Event-Eigenschaften * @param string|null $userId Benutzer-ID (optional) */ public function track(string $event, array $properties = [], ?string $userId = null): void ``` ## Namenskonventionen - **Klassen**: PascalCase (`AnalyticsManager`) - **Methoden/Funktionen**: camelCase (`getEventStats()`) - **Variablen**: camelCase (`$eventData`) - **Konstanten**: SNAKE_CASE (`MAX_BATCH_SIZE`) - **Dateien**: Klassenname.php (`AnalyticsManager.php`) ## Architektur - Dependency Inversion Principle befolgen - Interfaces für alle externen Abhängigkeiten - Vermeide zirkuläre Abhängigkeiten zwischen Modulen - Services sollten eine klare, fokussierte Verantwortung haben ## Performance - Lazy Loading für ressourcenintensive Operationen - Caching wo sinnvoll - Datenstrukturen sorgfältig auswählen ## Security - Alle Benutzereingaben validieren und bereinigen - Prepared Statements für Datenbankabfragen - Vermeidung von `eval()` und ähnlichen unsicheren Funktionen - Sensible Daten niemals in Logs schreiben ## Best Practices - **Immutability**: Bevorzuge unveränderliche Objekte - **Pure Functions**: Bevorzuge reine Funktionen ohne Seiteneffekte - **Enums**: Verwende Enums statt String-Konstanten für feste Optionssätze - **DTOs**: Verwende Data Transfer Objects für Datentransport - **Value Objects**: Verwende Value Objects für semantisch reiche Datentypen ## Refactoring - Code, der diese Guidelines nicht erfüllt, sollte beim Bearbeiten aktualisiert werden - Tests müssen vor und nach dem Refactoring bestehen - Große Refactorings sollten in kleinen, separaten Commits erfolgen