October 5th 2025
The #[MustUseResult]
attribute prevents subtle bugs, however due to a recent RFC I'd recommend another approach going forward.
Adding #[MustUseResult]
(from the PHP language extensions library) to a function or method means that the result must be used by the calling code.
Consider a Money
class like this:
final class Money {
public function __construct(public readonly int $cents)
{}
#[MustUseResult]
public function add(int $cents): self
{
return new self($cents + $this->cents);
}
}
Note that the add
method returns a new instance of Money
, rather than updating the existing object.
On the face of it, the code below looks correct. However, the $money::cents
property is not updated by calling the add
method.
Instead add
returns a new instance of the Money
object, this new object has the cents
property set to 30.
$money = new Money(10);
$money->add(20); // This has no effect
echo $money->cents; // Value is 10
Due to the #[MustUseResult]
attribute, the code above would have an error on the $money->add(20);
line:
Result returned by method must be used
The correct way of using the add
method is:
$money = new Money(10);
$updated = $money->add(20);
echo $updated->cents; // Value is 30
The#[MustUseResult]
attribute helps developers use the code correctly.
Since creating #[MustUseResult]
PHP has introduced, from version 8.5, the #[NoDiscard]
attribute. (RFC).
#[NoDiscard]
and #[MustUseResult]
do pretty much the same thing. A benefit of #[NoDiscard]
is errors also are reported running the code and not just by static analysis.
Even if you are running PHP under 8.5, PHPStan still understands #[NoDiscard]
and will report errors.
Using either #[NoDiscard]
or #[MustUseResult]
is a powerful way to document (to both developers and tools) the intention of how a method should be used, thus preventing bugs.