Large Class
debt(d5/e7/b7/t5)
Closest to 'specialist tool catches it' (d5). The detection_hints list phpmd, phploc, phpmetrics, and sonarqube — all specialist static analysis tools rather than default linters or compilers. The concept is detectable automatically (automated: yes) but only when these tools are configured and run, not by a standard linter or compiler.
Closest to 'cross-cutting refactor across the codebase' (e7). The quick_fix describes identifying cohesive method groups and extracting classes, but common_mistakes highlight that shared private state must be exposed first, method clustering signals must be interpreted, and callers throughout the codebase must be updated. This is rarely a single-component fix — extracted classes ripple through all call sites, tests, and dependency injection configurations.
Closest to 'strong gravitational pull' (e7, mapped to b7). The applies_to covers web, cli, and queue-worker contexts — broad reach. A large class that has grown to 2000 lines with entangled state shapes every change made to that subsystem: new features get added to the blob rather than extracted, tests become unwieldy, and every future maintainer must navigate the full class to make safe changes. It exerts gravitational pull that grows over time.
Closest to 'notable trap — a documented gotcha most devs eventually learn' (t5). The misconception field explicitly states the trap: developers believe a large class is acceptable if it is well-organised internally (e.g., neat regions or comments), when in fact size itself signals SRP violation regardless of internal organisation. A common_mistake reinforces this — treating 'related' as sufficient justification. This is a well-known gotcha that most developers encounter and eventually learn, but it consistently fools beginners.
Also Known As
TL;DR
Explanation
The Large Class smell is the class-level equivalent of Long Method. A class doing too much usually has many instance variables, low cohesion — clusters of methods and fields that are only loosely related. The refactoring is Extract Class: identify cohesive clusters and move them into dedicated classes connected by composition. Common triggers: class names containing 'Manager', 'Handler', 'Utils', or 'Service' that have grown past 500 lines; classes with 20+ instance variables where different subsets are used in different methods; or classes modified for nearly every feature change (a Divergent Change smell).
Common Misconception
Why It Matters
Common Mistakes
- Treating 'related' as sufficient justification for keeping methods together — everything in a domain is related.
- Not using method groups as a refactoring signal — if private methods naturally cluster, extract a class.
- Large classes that are hard to split because of shared private state — expose state via focused public methods before extracting.
- Measuring size only in lines — a class with 50 methods of 2 lines each is still too large.
Code Examples
// One class does everything — 2000 lines, 50 methods
class UserService {
public function register() {}
public function login() {}
public function resetPassword() {}
public function updateProfile() {}
public function sendVerificationEmail() {}
public function generateAuthToken() {}
public function revokeToken() {}
public function checkPermissions() {}
// 42 more methods...
}
// Split by single responsibility
class UserRegistrationService { public function register(RegisterRequest \$r): User {} }
class UserAuthService { public function login(Credentials \$c): AuthToken {} }
class PasswordResetService { public function reset(string \$email): void {} }
class ProfileService { public function update(int \$id, array \$data): User {} }
class UserPermissionService { public function can(User \$u, string \$action): bool {} }