Tell Don't Ask Principle
debt(d7/e5/b5/t5)
Closest to 'only careful code review or runtime testing' (d7). The detection_hints indicate automated detection is 'no' and while phpstan is listed as a tool, it cannot reliably detect TDA violations as a general rule — it would only catch specific patterns. The code_pattern shows the smell is contextual (is this getter driving logic that belongs in the object?) and requires a reviewer to understand domain responsibilities, not a static analysis rule.
Closest to 'touches multiple files / significant refactor in one component' (e5). The quick_fix says 'move logic into the class that owns the data', which sounds simple, but in practice the common_mistakes describe feature envy and anemic domain models — patterns that often permeate a service layer or domain, requiring logic to be redistributed across multiple classes and their callers, touching multiple files per fix instance.
Closest to 'persistent productivity tax' (b5). Applies across web, cli, and queue-worker contexts (broad applies_to). Violating TDA consistently leads to anemic domain models, which slow down every future domain change as logic is scattered in services rather than in the objects that own the data. It's not purely architectural (b7/b9) but it does persistently tax maintainers across many work streams.
Closest to 'notable trap (a documented gotcha most devs eventually learn)' (t5). The misconception field explicitly states the trap: developers believe TDA means 'never read state from objects', but it actually only prohibits querying state to make decisions the object itself should make. Getters for display/reporting are fine. This is a well-documented nuance that most developers misunderstand until they've been corrected, aligning with t5.
Also Known As
TL;DR
Explanation
Tell Don't Ask (Pragmatic Programmers / Martin Fowler) states that you should command objects to perform operations rather than querying their state and acting on it externally. Asking for data and making decisions outside the object is procedural thinking dressed in classes. The fix is to move the decision logic inside the object — this is often a feature envy refactoring and increases cohesion. It doesn't mean getter methods are always wrong, but their use should be questioned.
Common Misconception
Why It Matters
Common Mistakes
- Querying object state to make a decision and then calling a method based on it — give the object the decision.
- if ($user->isAdmin()) $user->setPermission('all') — the User should handle permission assignment internally.
- Feature envy: a service that queries every property of a domain object to compute something the object could compute.
- Confusing TDA with avoiding queries entirely — queries for display or reporting are fine; avoid them for behaviour decisions.
Code Examples
// ASK — pulling data out to make decisions
if ($user->getAccount()->getBalance() < $order->getTotal()) {
throw new InsufficientFundsException();
}
// TELL — give the object the information and let it decide
$user->getAccount()->debit($order->getTotal()); // Account throws InsufficientFundsException internally