Middle Man
debt(d5/e3/b5/t5)
Closest to 'specialist tool catches it' (d5), because detection_hints list phpmd and phpstan as the relevant tools, and automated detection is flagged as 'no' — meaning even these tools only partially surface the smell via heuristics (>50% pass-through methods). It won't be caught by a compiler or default linter, requiring a specialist static analysis tool and still needing human judgment to confirm.
Closest to 'simple parameterised fix' (e3), because the quick_fix describes inlining the delegation so callers call the real class directly. This is a mechanical refactor — removing the middle-man class and updating its call sites — which typically spans a handful of files within one component rather than a true cross-cutting rework.
Closest to 'persistent productivity tax' (b5), because middle-man classes accumulate over time (common_mistakes note they are never deleted after extraction), and they apply across web, cli, and queue-worker contexts. Every maintainer must navigate an extra indirection layer when reading or modifying code, slowing comprehension across multiple work streams without fully defining the system's architecture.
Closest to 'notable trap' (t5), because the misconception field states that developers commonly believe delegation is always better than direct access — a documented OOP gotcha. A competent developer familiar with delegation patterns from DDD may not recognise when wrapping crosses into valueless pass-through, making this a well-known but non-obvious pitfall that most developers eventually learn.
Also Known As
TL;DR
Explanation
The Middle Man smell occurs when a class primarily exists to forward calls to another class, offering no additional logic or value. It arises from over-application of delegation or from classes that were once more substantial but had their behaviour stripped out. The remedy is typically to remove the intermediary and call the delegate directly (inline delegation), or if the class is a legitimate abstraction, to add real behaviour to justify its existence.
Common Misconception
Why It Matters
Common Mistakes
- Service classes that are pure pass-throughs to a repository with no added logic.
- Facade classes that expose every method of the subsystem 1:1 without simplification.
- Not removing middle men during refactoring — they accumulate when classes are extracted but the original is never deleted.
- Over-using delegation patterns from DDD without checking whether each layer adds value.
Code Examples
// UserManager just delegates every call — pointless layer
class UserManager {
public function __construct(private UserRepository $repo) {}
public function find(int $id): ?User { return $this->repo->find($id); }
public function save(User $u): void { $this->repo->save($u); }
public function delete(int $id): void { $this->repo->delete($id); }
}
// Remove the middle man — inject UserRepository directly where needed
class UserController {
public function __construct(private UserRepository $users) {}
// use $this->users directly — no useless delegation layer
}