SOLID Principles (Overview)
debt(d7/e7/b7/t5)
Closest to 'only careful code review or runtime testing' (d7). The detection_hints explicitly state automated=no, meaning phpstan/psalm/phpcs can flag surface indicators (500+ line classes, new SomeClass() inside methods) but cannot detect true SOLID violations — those require human architectural review. No tool can confirm whether SRP or OCP is genuinely satisfied.
Closest to 'cross-cutting refactor across the codebase' (e7). The quick_fix describes extracting dependencies into interfaces and injecting them through constructors, but SOLID violations typically compound across many classes and layers. Correcting a codebase that ignored SOLID means restructuring multiple interdependent components — not a single-file change. The common_mistakes reinforce that these are systemic patterns, not isolated fixes.
Closest to 'strong gravitational pull' (b7). SOLID applies across web, cli, and queue-worker contexts (full applies_to breadth). The principles shape how every class, interface, and dependency is structured. A codebase that violates or misapplies SOLID imposes a persistent productivity tax on every maintainer — every new feature and refactor is shaped by the existing structural choices. Slightly below b9 because it doesn't literally redefine the system's runtime shape.
Closest to 'notable trap — a documented gotcha most devs eventually learn' (t5). The misconception field explicitly states the trap: treating SOLID as a strict ruleset rather than contextual guidelines leads to unnecessary complexity (e.g. interfaces for every class). The common_mistakes reinforce this with over-engineering patterns like premature strategy objects and naming-as-SRP. This is a well-documented pitfall but not a contradiction of a similar concept elsewhere, keeping it at t5.
Also Known As
TL;DR
Explanation
SOLID is an acronym for five related OO design principles: Single Responsibility (a class has one reason to change), Open/Closed (open for extension, closed for modification), Liskov Substitution (subclasses substitute for base classes), Interface Segregation (many specific interfaces over one general one), and Dependency Inversion (depend on abstractions, not concretions). Applied together they produce loosely coupled, highly cohesive code that is easy to test and extend. They are guidelines, not rules — apply them where they add value.
Common Misconception
Why It Matters
Common Mistakes
- Treating SOLID as dogma and applying all five principles to simple utility functions — they target complex, change-prone code.
- Confusing Interface Segregation with having one method per interface — it means interfaces should match client needs, not be maximally small.
- Implementing Open/Closed by wrapping everything in strategy objects before there is a real extension need.
- Naming classes *Service or *Manager and calling it SRP — naming does not guarantee single responsibility.
Avoid When
- Small scripts and one-off utilities — applying all five principles adds abstraction overhead with no maintenance benefit.
- Applying SOLID dogmatically — creating interfaces for classes that will never have a second implementation is over-engineering.
- Using SOLID as a checklist rather than guidelines — understanding the problem each principle solves matters more than compliance.
When To Use
- Long-lived codebases that will be extended by multiple developers over time.
- Any class that is becoming hard to test — testability problems usually signal a SOLID violation.
- When adding a new feature requires modifying many existing classes — open-closed principle applies.
- Library and framework code where consumers need to extend behaviour without modifying your source.
Code Examples
class Report {
public function generate() { /* logic */ }
public function saveToDatabase() { /* DB */ }
public function exportToPdf() { /* PDF */ }
public function sendByEmail() { /* mail */ }
// Violates SRP, OCP, and DIP simultaneously
}
class Report {
public function generate(): ReportData { /* pure logic */ }
}
class ReportExporter {
public function __construct(private ExporterInterface $exporter) {}
public function export(ReportData $data): void {
$this->exporter->export($data);
}
}