- Add DISCOVERY_LOG_LEVEL=debug - Add DISCOVERY_SHOW_PROGRESS=true - Temporary changes for debugging InitializerProcessor fixes on production
5.9 KiB
5.9 KiB
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
finalsein, es sei denn, es gibt einen zwingenden Grund für Vererbung - Keine abstrakten Klassen - bevorzuge Interfaces und Kompositionen
- Klassen sollten
readonlysein, wann immer möglich - Interfaces verwenden, um Verträge zwischen Komponenten zu definieren
// Gut
final readonly class AnalyticsManager
{
// ...
}
// Vermeiden
abstract class BaseManager
{
// ...
}
Properties
- Properties sollten
readonlysein, 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
// 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
// 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
// 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
public function findUser(?int $id): ?User
public function process(int|string $identifier): void
Match Expression statt Switch
// 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
$this->createUser(
email: 'user@example.com',
role: 'admin',
sendWelcomeEmail: true
);
Constructor Property Promotion
public function __construct(
private readonly Configuration $config,
private readonly PathProvider $pathProvider
) {}
Fehlerbehandlung
- Spezifische Exceptions werfen
- Typed Exceptions verwenden
- Early Return Pattern bevorzugen
// 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
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
/**
* 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