A get hook that looked like a property, read like a property, and issued a database query.
// what I wrote
public ?Invoice $invoice {
get => $this->invoices->findForOrder($this->id);
}
// and the loop somebody wrote three weeks later
foreach ($orders as $order) {
if ($order->invoice !== null) { /* ... */ }
}
// 200 queries, and nothing at the call site suggests it
The rule I wrote down in December — pure, cheap and total — was violated within a quarter by the person who wrote the rule. A hook makes work invisible, and invisible work in a loop is the oldest performance bug there is. It went back to invoice(), which is uglier and honest about being a call.