Design Patterns in PHP
Erste Schritte – Design Patterns in PHP: MVC, Singleton und Co.
Design Patterns sind bewährte Lösungsschablonen für wiederkehrende Architekturprobleme.
In PHP begegnen dir besonders häufig das MVC‑Paradigma für Web‑Apps und klassische GoF‑Patterns wie Singleton, Factory oder Observer.
Dieses Tutorial erklärt Grundidee, Vor- und Nachteile – inklusive kurzer Code‑Skizzen (ausschließlich in <pre>).
1. MVC – Model • View • Controller
- Model – Daten‑ & Geschäftslogik (DB‑Zugriffe, Validierung).
- View – Präsentationsschicht (HTML/JSON-Ausgabe).
- Controller – Vermittler, nimmt Request entgegen, ruft Model, wählt View.
/* Router‑Snippet */ $router->add('/user/{id}', 'UserController@show'); /* Controller (app/Controller/UserController.php) */ class UserController { public function show(int $id) { $user = User::find($id); // Model View::render('user/show', [ // View 'user' => $user ]); } }
Vorteil: Saubere Trennung, erleichtert Tests & Wartung.
Nachteil: Mehr Boilerplate, kann bei sehr kleinen Scripts überdimensioniert wirken.
2. Singleton – genau eine Instanz
Stellt sicher, dass eine Klasse nur ein Objekt besitzt (z. B. Konfig‑Manager, Logger).
class Logger { private static ?Logger $instanz = null; private function __construct() {} // privat public static function get(): Logger { if (self::$instanz === null) { self::$instanz = new self(); } return self::$instanz; } public function info(string $msg): void { error_log($msg); } } /* Nutzung */ Logger::get()->info('Start');
Vorteil: Globale, gemeinsam genutzte Ressource (DB, Config).
Nachteile: Schwer testbar, kann zu versteckter Abhängigkeit und Tight Coupling führen.
In modernen Projekten oft lieber Dependency‑Injection + Container einsetzen.
3. Factory – Objekterzeugung entkoppeln
Die Factory übernimmt komplexe Logik, welches konkrete Objekt zurückgegeben werden soll.
interface Payment { public function pay(float $summe): bool; } class PayPal implements Payment { /* … */ } class Stripe implements Payment { /* … */ } class PaymentFactory { public static function build(string $gateway): Payment { return match ($gateway) { 'paypal' => new PayPal(), 'stripe' => new Stripe(), default => throw new RuntimeException('Gateway?') }; } } $pay = PaymentFactory::build('paypal'); $pay->pay(42.0);
Vorteil: Aufrufende Klassen kennen konkrete Implementierung nicht.
Nachteil: Zusätzliche Factory‑Klassen erhöhen Code‑Menge.
4. Observer / Event – lose gekoppelte Benachrichtigung
Mehrere Objekte können sich bei einem Subject registrieren und werden bei Änderungen informiert.
interface Listener { public function update(string $event): void; } class EventDispatcher { private array $listener = []; public function on(string $event, Listener $l): void { $this->listener[$event][] = $l; } public function dispatch(string $event): void { foreach ($this->listener[$event] ?? [] as $l) { $l->update($event); } } } class MailListener implements Listener { public function update(string $event): void { // Mail versenden } } /* Registrierung */ $bus = new EventDispatcher(); $bus->on('user.registered', new MailListener()); /* Auslösen */ $bus->dispatch('user.registered');
Vorteil: Sehr flexibel, Komponenten kennen sich nicht direkt.
Nachteil: Komplexeres Debugging, wer reagiert auf welches Event?
5. Zusammenfassung
- MVC – Architekturmuster für ganze Apps: Request → Controller → Model → View.
- Singleton – Eine Instanz, statisch abrufbar (sparsam einsetzen, testbar halten).
- Factory – Erzeugt passende Objekte, versteckt konkrete Klassen.
- Observer – Event‑System, lockert Kopplung zwischen Sender / Empfänger.
Fazit
Design Patterns sind keine starren Regeln, sondern Werkzeuge.
Wähle sie, wenn sie dein aktuelles Problem vereinfachen und zukünftige Erweiterungen erleichtern –
nicht, um Checklisten abzuarbeiten.
In PHP‑Projekten kombiniert man häufig MVC als Grundgerüst, Factories zur Objekterstellung,
Events für loses Coupling und – wo sinnvoll – Singletons für gemeinsam genutzte Services.