Object Calisthenics
debt(d7/e5/b3/t7)
Closest to 'only careful code review or runtime testing' (d7). The detection_hints indicate tools phpcs and phpstan are listed but automated detection is explicitly marked 'no'. The code patterns (multiple indentation levels, else clauses, raw primitives) require human judgment or code review to reliably identify — tooling can flag some surface patterns but not the design intent violations.
Closest to 'touches multiple files / significant refactor in one component' (e5). The quick_fix describes applying nine rules as a checklist, but common_mistakes show that wrapping primitives (Email value objects), extracting methods aggressively, and eliminating else/getters are structural changes that typically touch multiple files and require non-trivial refactoring across a component, not a single-line patch.
Closest to 'localised tax' (b3). Applies broadly to web, cli, and queue-worker contexts per applies_to, but the burden is primarily on code review and developer habits rather than imposing architectural gravity on the codebase. It is a persistent but localised tax — it shapes how individual methods and classes are written without dictating system-wide architecture.
Closest to 'serious trap' (t7). The misconception field explicitly states the canonical wrong belief: developers treat the nine rules as mandatory production standards rather than intentional exercises. This contradicts how similar 'principles' (like SOLID) are used elsewhere — those are production guidelines, whereas object calisthenics are training constraints. A competent developer encountering these rules will very likely misapply them as absolute laws.
Also Known As
TL;DR
Explanation
Object Calisthenics are nine constraints: (1) one level of indentation per method, (2) no else keyword, (3) wrap all primitives and strings, (4) first-class collections, (5) one dot per line, (6) no abbreviations, (7) keep classes small, (8) no classes with more than two instance variables, (9) no getters/setters. They are deliberately strict — intended as an exercise rather than production rules — but applying them surfaces design improvements, encourages value objects, and reduces coupling.
Common Misconception
Why It Matters
Common Mistakes
- Treating all nine rules as mandatory production standards — they are learning exercises, not absolute laws.
- Only one level of indentation is the most impactful rule and the most ignored — extract methods aggressively.
- Not wrapping primitives and strings — string $email should be an Email value object that validates itself.
- No else — forcing early return and guard clauses rather than nested if/else is the high-value take-away.
Code Examples
// Violates multiple calisthenics rules — 3 levels of nesting, else branches, raw primitives:
function process(array $data): string {
if (!empty($data)) {
foreach ($data as $item) {
if ($item['type'] === 'A') {
return $item['value'];
} else {
return 'default';
}
}
} else {
return 'empty';
}
}
// 9 rules applied pragmatically:
// 1. One level of indentation per method — extract nested logic
public function process(array \$items): array {
return array_filter(\$items, fn(\$i) => \$this->isValid(\$i));
}
// 2. No else — early return instead
public function find(int \$id): User {
if (!\$id) throw new \InvalidArgumentException();
return User::findOrFail(\$id);
}
// 3. Wrap primitives — value objects
\$email = new Email(\$rawEmail);
// 4. First-class collections
class UserCollection {
public function __construct(private array \$users) {}
public function active(): self {
return new self(array_filter(\$this->users, fn(\$u) => \$u->isActive()));
}
}