Lazy Class
debt(d7/e3/b3/t5)
Closest to 'only careful code review or runtime testing' (d7). The detection_hints indicate tools like phpmd and phpstan can flag some cases, but automated detection is explicitly marked 'no' — these tools can surface candidates but cannot reliably confirm a class is truly 'lazy' without human judgment about intent and context. A reviewer must assess whether the abstraction is genuinely unjustified.
Closest to 'simple parameterised fix (replace pattern with safer alternative)' (e3). The quick_fix is 'inline the lazy class into its only caller,' which is typically a small, localised refactor — collapsing one class into one caller. It touches the class file and its single caller, but rarely spreads further.
Closest to 'localised tax (one component pays, rest of codebase unaffected)' (b3). A lazy class adds indirection and an extra file to navigate, but its reach is inherently limited by its definition — it has few callers and little logic. The burden is real but constrained to the immediate area of the codebase.
Closest to 'notable trap (a documented gotcha most devs eventually learn)' (t5). The misconception is 'every abstraction justifies its own class,' which is a widely held OOP belief that leads developers to create lazy classes in good faith, especially under YAGNI pressure. Competent developers trained in OOP instinctively reach for a class and genuinely do not recognise the smell until they've been burned by navigational overhead.
Also Known As
TL;DR
Explanation
Lazy Class is the inverse of God Class: a class so small or trivial that it adds complexity without adding value. It may be the remnant of planned functionality that was never completed, or a class created through over-engineering that could simply be a method, a constant, or data on another class. The fix is either to inline the class into its caller (if it has one consumer) or to merge it with a related class that would benefit from its functionality.
Common Misconception
Why It Matters
Common Mistakes
- Creating a class to wrap a single function call — a plain function or static method is clearer.
- Abstract classes with only one concrete subclass — inline the subclass or make the abstract concrete.
- Data transfer objects that are never validated or enriched — use an array or typed array instead.
- Classes created 'for future extensibility' without a current use case — YAGNI applies.
Code Examples
// Class with a single trivial method — doesn't justify its existence
class StringHelper {
public function upper(string $s): string { return strtoupper($s); }
}
// Just call strtoupper() directly
// A class is justified when it encapsulates state + meaningful behaviour:
class CurrencyFormatter {
public function __construct(private string $locale, private string $currency) {}
public function format(int $cents): string {
return NumberFormatter::create($this->locale, NumberFormatter::CURRENCY)
->formatCurrency($cents / 100, $this->currency);
}
}