SOLID-Prinzipien in der Praxis
Wenden Sie die fünf SOLID-Prinzipien auf echte PHP-Klassen an.
SOLID-Prinzipien in der Praxis ist eine kostenlose PHP Academy-Lektion auf CoddyKit. Dies ist Lektion 1 von 4. Du kannst die komplette Lektion unten kostenlos lesen – dann übst du sie direkt im Browser mit einem integrierten Code-Editor und einem KI-Tutor rund um die Uhr. Sie ist Teil des PHP Academy-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der PHP Academy-Kurs umfasst insgesamt 4 Lektionen.
Warum SOLID
SOLID umfasst fünf Designprinzipien, die objektorientiertes PHP flexibel, testbar und resistent gegen Code-Verfall halten. Sie sind keine Regeln, die Sie blind befolgen sollten, sondern Heuristiken, die Kopplung reduzieren und Verantwortlichkeiten klarer machen. In dieser Lektion wenden wir jedes Prinzip auf konkrete PHP-Klassen an, die Sie tatsächlich in der Praxis einsetzen würden.
- Single Responsibility
- Open/Closed
- Liskov Substitution
- Interface Segregation
- Dependency Inversion
Einzelverantwortung
Eine Klasse sollte nur einen Grund für eine Änderung haben. Eine Klasse, die einen Bericht erstellt, ihn als HTML formatiert und per E-Mail versendet, hat drei Änderungsgründe. Trennen Sie Persistenz, Formatierung und Transport.
Unten modelliert Invoice ausschließlich Daten; Darstellung und Speichern liegen an anderer Stelle.
<?php
final class Invoice {
public function __construct(
public readonly string $number,
public readonly int $cents
) {}
public function total(): float { return $this->cents / 100; }
}
final class InvoiceRenderer {
public function toText(Invoice $i): string {
return sprintf('Invoice %s: $%.2f', $i->number, $i->total());
}
}
$i = new Invoice('INV-1', 12500);
echo (new InvoiceRenderer())->toText($i), PHP_EOL;
SRP: Code-Smells erkennen
Der klassische SRP-Verstoß ist eine Klasse, deren Name und enthält, oder ein Manager, der alles erledigt. Achten Sie auf Methoden, die sich aus voneinander unabhängigen fachlichen Gründen ändern. Wenn eine Änderung der Steuerregeln und eine Änderung des PDF-Layouts dieselbe Klasse betreffen, hat sie zu viele Verantwortlichkeiten.
Open/Closed-Prinzip
Softwareeinheiten sollten für Erweiterungen offen und für Änderungen geschlossen sein. Das Hinzufügen eines neuen Rabatttyps sollte keine Änderungen an einem riesigen switch erzwingen. Verwenden Sie Polymorphie: Jede Regel ist eine eigene Klasse, die eine gemeinsame Schnittstelle implementiert.
<?php
interface Discount { public function apply(float $total): float; }
final class PercentOff implements Discount {
public function __construct(private float $pct) {}
public function apply(float $t): float { return $t * (1 - $this->pct / 100); }
}
final class FlatOff implements Discount {
public function __construct(private float $amount) {}
public function apply(float $t): float { return max(0, $t - $this->amount); }
}
function checkout(float $total, Discount ...$discounts): float {
foreach ($discounts as $d) { $total = $d->apply($total); }
return $total;
}
echo checkout(100, new PercentOff(10), new FlatOff(5)), PHP_EOL; // 85
Liskov-Substitution
Untertypen müssen überall dort verwendbar sein, wo ihr Basistyp erwartet wird, ohne den Aufrufer zu überraschen. Das berüchtigte Beispiel Square extends Rectangle verletzt das LSP, weil das Setzen der Breite nicht stillschweigend die Höhe ändern darf. Modellieren Sie sie vorzugsweise als separate Typen hinter einer gemeinsamen Shape-Schnittstelle.
<?php
interface Shape { public function area(): float; }
final class Rectangle implements Shape {
public function __construct(private float $w, private float $h) {}
public function area(): float { return $this->w * $this->h; }
}
final class Square implements Shape {
public function __construct(private float $side) {}
public function area(): float { return $this->side ** 2; }
}
$shapes = [new Rectangle(2, 3), new Square(4)];
foreach ($shapes as $s) { echo $s->area(), PHP_EOL; }
LSP und Verträge
LSP schränkt auch Methodenverträge ein. Ein Untertyp darf Vorbedingungen abschwächen und Nachbedingungen verschärfen, niemals umgekehrt. Das Auslösen eines neuen Ausnahmetyps, den die Basisklasse nie deklariert hat, oder die Rückgabe von null, obwohl die Basisklasse ein Objekt garantiert, verletzt die Ersetzbarkeit. PHPs kovariante Rückgabetypen und kontravariante Parametertypen setzen davon einen Teil auf Typebene durch.
Interface Segregation
Clients sollten nicht von Methoden abhängen, die sie nicht verwenden. Eine überfrachtete Worker-Schnittstelle mit work() und eat() zwingt einen RobotWorker, für eat() einen Stub bereitzustellen. Teilen Sie sie in fokussierte Rollen-Schnittstellen auf, damit jeder Implementierer sich nur zu dem verpflichtet, was er tatsächlich tut.
<?php
interface Workable { public function work(): string; }
interface Feedable { public function eat(): string; }
final class Human implements Workable, Feedable {
public function work(): string { return 'coding'; }
public function eat(): string { return 'lunch'; }
}
final class Robot implements Workable {
public function work(): string { return 'welding'; }
}
foreach ([new Human(), new Robot()] as $w) { echo $w->work(), PHP_EOL; }
Dependency Inversion
Richtlinien auf hoher Ebene sollten von Abstraktionen abhängen, nicht von konkreten Details. Injizieren Sie eine Schnittstelle, keine fest verdrahtete Klasse. So können Sie einen echten Mailer in Tests durch einen Fake und in der Produktion durch einen anderen Anbieter ersetzen, ohne den nutzenden Code anzupassen.
<?php
interface Mailer { public function send(string $to, string $body): void; }
final class SmtpMailer implements Mailer {
public function send(string $to, string $body): void {
echo "SMTP -> $to: $body" . PHP_EOL;
}
}
final class SignupService {
public function __construct(private Mailer $mailer) {}
public function register(string $email): void {
$this->mailer->send($email, 'Welcome!');
}
}
(new SignupService(new SmtpMailer()))->register('a@b.com');
DIP und der Container
Dependency Inversion ist das Prinzip; Dependency Injection ist eine Technik, um es umzusetzen. Ein DI-Container (PSR-11) verdrahtet den konkreten SmtpMailer mit der Abstraktion Mailer am Composition Root. Der nutzende Code schreibt niemals new SmtpMailer(); dadurch zeigt die Richtung der Abhängigkeit im Quellcode auf die Abstraktion und nicht auf das Detail.
<?php
// Composition root wiring (pseudo-container)
$bindings = [
Mailer::class => fn() => new SmtpMailer(),
];
$resolve = fn(string $id) => $bindings[$id]();
$service = new SignupService($resolve(Mailer::class));
$service->register('user@example.com');
SOLID gemeinsam
Die Prinzipien ergänzen und verstärken sich gegenseitig. ISP hält Schnittstellen klein, sodass DIP-Injektionen fokussiert bleiben; OCP basiert auf Polymorphie, die durch LSP sicher bleibt; SRP liefert die kleinen Klassen, die all dies ermöglichen. Streben Sie nach hoher Kohäsion innerhalb und loser Kopplung zwischen Einheiten.
- Abstrahieren Sie eine nur einmal verwendete Klasse nicht übermäßig.
- Führen Sie eine Schnittstelle ein, sobald eine zweite Implementierung oder ein Test-Double hinzukommt.
Pragmatismus
SOLID ist ein Mittel, kein Selbstzweck. Eine vorzeitig eingeführte Schnittstelle mit nur einer Implementierung erzeugt ohne Nutzen zusätzliche Indirektion („spekulative Generalisierung“). Wenden Sie die Prinzipien an, wenn tatsächlich Änderungen anstehen oder eindeutig absehbar sind. In Richtung SOLID zu refaktorieren ist mit vorhandenen Tests günstig; am ersten Tag blind in diese Richtung zu refaktorieren ist Verschwendung.
Kurzer Check
Welches Prinzip verletzt das Vererbungsproblem mit Square und Rectangle?
Rückblick
Sie haben alle fünf SOLID-Prinzipien auf praktischen PHP-Code angewendet:
- SRP: ein Änderungsgrund pro Klasse.
- OCP: Erweiterung durch neue polymorphe Klassen statt durch Änderungen an einem switch.
- LSP: Untertypen halten den Vertrag des Basistyps ein.
- ISP: kleine Rollen-Schnittstellen statt überfrachteter Schnittstellen.
- DIP: Abhängigkeit von Abstraktionen, Details werden am Composition Root injiziert.
Nutzen Sie sie als Leitlinien für Refactorings, nicht als Selbstzweck.
Häufig gestellte Fragen
Ist die Lektion „SOLID-Prinzipien in der Praxis“ kostenlos?
Ja — der vollständige Text von „SOLID-Prinzipien in der Praxis“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des PHP Academy-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der PHP Academy-Kurs umfasst insgesamt 4 Lektionen.
Was lerne ich in „SOLID-Prinzipien in der Praxis“?
Wenden Sie die fünf SOLID-Prinzipien auf echte PHP-Klassen an. Du übst PHP Academy mit praktischem Code, den du direkt im Browser ausführst, und ein 24/7 KI-Tutor beantwortet deine Fragen während du die Lektion bearbeitest.
Brauche ich Erfahrung, um PHP Academy zu starten?
Keine Vorkenntnisse erforderlich. PHP Academy auf CoddyKit ist für Anfänger bis fortgeschrittene Lernende strukturiert, sodass du hier starten oder von Anfang an beginnen und in deinem eigenen Tempo voranschreiten kannst. Dies ist Lektion 1 von 4.
Wie lange dauert die Lektion „SOLID-Prinzipien in der Praxis“?
Die meisten CoddyKit-Lektionen dauern etwa 5–10 Minuten. Jede ist kompakt und interaktiv, sodass du stetig Fortschritte machst und genau dort weitermachst, wo du aufgehört hast – im Web und in der App.
Kann ich in dieser PHP Academy-Lektion Code schreiben und ausführen?
Ja. Jede PHP Academy-Lektion enthält einen integrierten Code-Editor, sodass du echten Code direkt in deinem Browser schreibst und ausführst und sofort KI-Feedback erhältst — ohne lokale Einrichtung erforderlich.
Alle Lektionen in diesem Kurs
- SOLID-Prinzipien in der Praxis
- Erzeugungsmuster: Factory, Builder, Singleton
- Strukturelle Muster: Adapter, Decorator, Facade
- Verhaltensmuster: Strategy, Observer, Command