The PHP attribute that yells at you for ignoring a return value: #[\NoDiscard] in 8.5
PHP 8.5 shipped a small attribute with an unusually specific job: it makes the language yell at you for ignoring a function's return value. It's called #[\NoDiscard], and unlike most of the attributes we've gotten lately, it doesn't document intent for some tool to read later — it improves your code by nagging you, at runtime, the moment you make a classic mistake. I've grown fond of it precisely because it's so narrow.
The bug it targets
There's a whole class of functions where the return value is the point — pure functions and immutable APIs that don't mutate anything, they hand you back a new thing. The footgun is calling one and forgetting to use what it gives you:
$url->withScheme('https'); // oops — did nothing you can see
$config->set('key', 'val'); // returns a NEW config; the old one is unchanged
Both lines look like they did something. Both quietly did nothing, because the result was thrown away. #[\NoDiscard], applied to the function, tells PHP to emit a warning when the returned value isn't consumed. Add an optional message and it's appended to the warning, exactly like #[\Deprecated]: #[\NoDiscard("the result must be assigned; the original is unchanged")].
When you genuinely mean to discard the result, you say so explicitly with a (void) cast — (void)$logger->withContext($ctx); — which silences the warning and, better, documents that the discard was on purpose. One sharp edge worth knowing: the (void) cast is a statement, not an expression, so you can't use it inside an if(...) or an assignment; it only works as a standalone call. A small wart, but you'll hit it once and remember.
Why this matters in Drupal-land specifically
Drupal is full of exactly the shape this protects. Every immutable-ish value object and fluent withX() setter is a #[\NoDiscard] candidate: the Url object, cacheability metadata you're bubbling, address and DTO-style config objects, anything where the method returns a modified copy rather than mutating in place. I have personally shipped the "I called ->addCacheableDependency() and forgot to use the result" bug and lost twenty minutes to it. An attribute that turns that into a warning at the call site is a small gift.
Most PHP attributes are notes to a static analyzer. This one is a note to you, delivered at the exact moment you're about to be wrong. That's a different and rarer kind of useful.
The honest caveats
Two things keep it from being magic. First, it's a warning, not an error — which in a Drupal log that's already noisy with deprecations and notices means it'll drown unless you do the grown-up thing and treat warnings as failures in CI. On its own, in production, nobody will ever see it. Second, the payoff is in your own code, today, not the ecosystem: core and contrib won't annotate their value objects with #[\NoDiscard] for years, so you don't get to lean back and let the framework catch your mistakes. You get the benefit by adding the attribute to the immutable APIs you write.
That's the realistic pitch. It's not going to change how you write Drupal this week. But the next time you build a value object or a fluent builder that returns a new instance instead of mutating, add #[\NoDiscard] to it, wire your CI to fail on warnings, and you've closed a whole category of silent bug for everyone who ever calls it — including future you, twenty minutes from a mistake you won't have to make.