Extract Class Refactoring
debt(d5/e5/b3/t3)
Closest to 'specialist tool catches it' (d5). The detection_hints list phpmd and sonarqube as the tools, both specialist static analysis tools that can flag large/low-cohesion classes via metrics. The automated field is explicitly 'no', meaning even these tools only hint at candidates rather than definitively catching the problem — but they are the primary detection mechanism, placing this squarely at d5.
Closest to 'touches multiple files / significant refactor in one component' (e5). The quick_fix describes identifying cohesive field groups, creating a new class, moving fields and their methods, and replacing all references in the original class. The common_mistakes note that not updating all references is a pitfall, confirming this spans at least two files (old class + new class) and requires careful cross-reference updates — more than a simple pattern replacement but not a full cross-cutting codebase refactor.
Closest to 'localised tax' (b3). The extraction affects the refactored class and its direct consumers, but the rest of the codebase is largely unaffected. The applies_to contexts are broad (web/cli/queue-worker), but the structural impact is localised to the component being refactored and its callers. Future maintainers only pay the tax if they work in that area.
Closest to 'minor surprise (one edge case)' (t3). The misconception states developers think Extract Class is only for God Classes, when in fact any class with a cohesive subset of responsibilities qualifies. This is a scoping misunderstanding rather than a behavioural trap — a competent developer won't make catastrophically wrong decisions, but may under-apply the technique. The common_mistakes (anaemic classes, missed references, over-extraction) add minor edge-case surprises, keeping this at t3.
TL;DR
Explanation
A class doing too much (God Class) should be split. Extract Class: identify a cohesive group of fields and methods (e.g., address-related fields in a User class), create a new class (Address), move the fields and methods, update the original class to hold a reference. Signs you need it: class has many unrelated fields, methods only use a subset of fields, natural groupings exist (User + Address, Order + PaymentDetails). In PHP: create the new class, inject it via constructor, update all references. Opposite of Inline Class.
Common Misconception
Why It Matters
Common Mistakes
- Creating classes with only getters/setters (anaemic) — extract behaviour too, not just data.
- Not updating all references after extraction — leaving the old fields in place as duplicates.
- Extracting too aggressively — small classes with one field and one method add unnecessary indirection.
Code Examples
class User {
public string $name;
public string $street;
public string $city;
public string $postcode;
public string $country;
public function formatAddress(): string {
return "$this->street, $this->city";
}
}
class Address {
public function __construct(
public readonly string $street,
public readonly string $city,
public readonly string $postcode,
public readonly string $country,
) {}
public function format(): string {
return "$this->street, $this->city";
}
}
class User {
public function __construct(
public readonly string $name,
public readonly Address $address,
) {}
}