A chain of null checks reads badly and the operator that replaces them is genuinely better — and it makes one specific mistake easier to write.
// the chain it replaces
$city = null;
if ($order !== null && $order->address() !== null) {
$city = $order->address()->city();
}
$city = $order?->address()?->city();
// and the mistake: this short-circuits the WHOLE chain
$total = $order?->lines()->sum(); // null, silently, if $order is null
// rather than an error saying lines() was called on null
Short-circuiting the entire expression rather than just the next access is correct and is what people do not expect — everything after the first null is skipped, including method calls that would otherwise have thrown. That turns a loud failure into a silent null propagating upward. It also cannot be used as a write target or with [] access, which are the two places people first try it.