Single Responsibility Principle
debt(d7/e7/b7/t7)
Closest to 'only careful code review or runtime testing' (d7). The detection_hints explicitly state automated=no. While phpstan and phpcs are listed as tools, they can flag heuristics like XxxManager/XxxHelper/XxxUtil with 10+ public methods, but this is a shallow proxy — the real violation (multiple reasons to change) requires human judgment during code review. No tool can reliably detect conceptual responsibility misalignment.
Closest to 'cross-cutting refactor across the codebase' (e7). The quick_fix says 'split it', but splitting a class that owns multiple concerns (e.g., a controller doing DB queries, business logic, and HTTP response building) typically requires extracting services, updating all call sites, and retesting across multiple files. When SRP is ignored during prototyping and the code 'works', the common_mistakes entry confirms it compounds — the refactor becomes cross-cutting rather than local.
Closest to 'strong gravitational pull' (b7). Applies across web, cli, and queue-worker contexts. A codebase that ignores SRP systematically produces tightly coupled classes that shape every subsequent change — every new feature must navigate the tangled responsibilities. The common_mistakes entry notes that most spaghetti codebases trace back to this, making it a persistent productivity tax with strong gravitational pull on all future development.
Closest to 'serious trap' (t7). The misconception field documents exactly the trap: developers commonly believe SRP means 'a class should only do one thing' (one action/method), when the actual principle is 'one reason to change' (one stakeholder/concern). This is a meaningful semantic difference that leads developers to either over-split (5-line helper classes for trivial operations) or under-split (conflating unrelated concerns as 'one thing'). It contradicts intuitive interpretations of the word 'single'.
Also Known As
TL;DR
Explanation
The S in SOLID, SRP states that every module, class, or function should be responsible for one part of the system's functionality. "One reason to change" means: if two different types of requirements changes would require editing the same class, that class probably has too many responsibilities. SRP makes code easier to understand, test, and modify because changes to one concern don't accidentally break another.
Common Misconception
Why It Matters
Common Mistakes
- Confusing SRP with "one method per class" — it means one reason to change, not one action.
- Putting database queries, business logic, and HTTP response building all inside a controller.
- Splitting too aggressively — a 5-line helper class for every trivial operation creates its own maintenance burden.
- Ignoring SRP during prototyping and never refactoring once the code "works".
Code Examples
class User {
public function save(): void { /* DB logic */ }
public function sendWelcomeEmail(): void { /* SMTP logic */ }
public function toJson(): string { /* serialisation */ }
public function validatePassword(string $pw): bool { /* validation */ }
// Four reasons to change
}
class OrderController {
public function store(Request $r, OrderService $orders) {
$order = $orders->create($r->validated());
return response()->json($order);
}
}
// OrderService handles business logic, dispatches events/jobs