Law of Demeter — PHP Examples
debt(d7/e5/b5/t5)
Closest to 'only careful code review or runtime testing' (d7). The detection_hints list phpmd and phpstan, but automated detection is explicitly marked 'no' — these tools can flag syntactic method chains but cannot reliably distinguish LoD violations (crossing object boundaries) from legitimate fluent interfaces on a single object. Human code review is required to make that judgment, placing this firmly at d7.
Closest to 'touches multiple files / significant refactor in one component' (e5). The quick_fix describes adding delegation methods (e.g., $order->getCustomerEmail()), which sounds like a local fix, but the common_mistakes note that simply adding getters to intermediates shifts not removes coupling, and the 'extended' analysis reveals systemic coupling patterns across many methods. Properly fixing LoD violations typically means restructuring how multiple collaborators communicate, touching several classes and possibly DTOs, putting this at e5.
Closest to 'persistent productivity tax' (b5). The term applies_to web, cli, and queue-worker — essentially the full PHP codebase scope. The 'extended' framing explicitly notes that systemic LoD violations are a coordination smell requiring structural change. Once coupling is baked in across many object traversals, every future change must navigate or work around those chains, imposing a persistent productivity tax, but it does not fully define the system's shape (not b7).
Closest to 'notable trap — a documented gotcha most devs eventually learn' (t5). The misconception field explicitly states the canonical wrong belief: that all method chaining is a LoD violation. Fluent interfaces on a single object are fine; the violation is navigating through multiple distinct objects. This is a well-known, documented gotcha that many developers get wrong initially (especially confusing builder/fluent patterns with train-wreck chains), placing this at t5.
Also Known As
TL;DR
Explanation
The Law of Demeter (LoD) states a method should only call methods on: itself, its parameters, objects it creates, and its direct fields. Chained calls like $order->getCustomer()->getAddress()->getCity()->getName() violate LoD — the method knows the entire object graph structure, creating hidden coupling. Every link in the chain is a dependency on internal structure that can break silently. The fix is Tell Don't Ask: add $order->getCustomerCity() that encapsulates the traversal. This is not a rigid rule against all fluent interfaces (builders, query builders designed for chaining are fine) but a smell detector for domain traversal chains. In PHP, long chains frequently appear in controller code accessing nested relationships — these belong in dedicated query methods or read models.
Common Misconception
Why It Matters
Common Mistakes
- Treating LoD violations as purely style issues — they are structural coupling that compounds over time.
- Using the Tell, Don't Ask principle only at the micro level without applying it to system design.
- Fixing LoD violations by adding getters to intermediate objects — this shifts not removes the coupling.
- Not using data transfer objects to carry information across boundaries rather than reaching through object graphs.
Code Examples
// Violates LoD — knows entire object graph
$city = $order->getCustomer()->getAddress()->getCity()->getName();
// Order encapsulates the traversal
$city = $order->getCustomerCity();