this post was submitted on 04 Jun 2025
10 points (91.7% liked)

Programming

0 readers
1 users here now

My various programming endeavours, mainly in PHP (Symfony), Typescript (Angular), Go and C#. With a sprinkle of Java and C++ here and there.

founded 4 months ago
MODERATORS
 

PHP 8.5 introduces a variety of compelling features. As a library author, I'm particularly thrilled by the addition of the built-in #[NoDiscard] attribute, enabling developers to mark a function or method's return value as important.

Tip: You can read the full RFC at wiki.php.net.

How does the NoDiscard attribute work?

Using #[NoDiscard] is straightforward—simply annotate your function or method. For example, marking a function that returns critical operation results, such as status flags or error messages, helps prevent accidental omission or unnoticed errors:

<?php

#[NoDiscard]
function processStuff(): array
{
    return [];
}

Now, if the function is called without using its return value, PHP generates the following warning:

The return value of function processStuff() should either be used or intentionally ignored by casting it as (void).

Customizing the Warning Message

You can provide a custom message for greater clarity:

<?php

#[NoDiscard("because this is a batch processing function, and if any of the items fail, it returns the error details in an array instead of throwing an exception.")]
function processStuff(): array
{
    return [];
}

This results in a more personalized warning:

The return value of function processStuff() is expected to be consumed, because this is a batch processing function, and if any of the items fail, it returns the error details in an array instead of throwing an exception.

Suppressing the Warning

Besides using the returned value (assigning or otherwise processing it), you can suppress this warning in several ways:

<?php

@processStuff();          // Error suppression operator
(void)processStuff();     // Explicit void cast
$_ = processStuff();      // If you're coming from Go ;)

However, beware of OPCache optimizations. If OPCache detects an unused instruction, it might optimize away the call, leading to inconsistencies between development and production environments.

<?php

(bool)processStuff(); // OPCache may ignore this because the result isn't used.

Using (void) explicitly is safe since OPCache will not optimize away explicit void casts.

Where is it used?

In addition to being usable in your own code, the #[NoDiscard] attribute is automatically applied to specific core PHP functions/methods, notably:

  • flock(): Ignoring its false return value can lead to difficult-to-diagnose concurrency issues.
  • Setters of DateTimeImmutable: These methods do not modify the original instance but return a new one. Ignoring this return value does nothing, a common pitfall for new developers.

When is the Warning Triggered?

PHP triggers the warning immediately before the function call executes, offering a significant safety benefit. If your application converts warnings into exceptions (as Symfony does by default), the potentially dangerous code never executes:

<?php

set_error_handler(function (int $errno, string $errstr, string $errfile, int $errline) {
    throw new ErrorException($errstr, 0, $errno, $errfile, $errline);
});

$file = fopen("/tmp/test.txt", "r+");
flock($file, LOCK_EX);
// Safe to write to the file! Or is it? We don't know because we ignored the return value of flock()
fwrite($file, "Hello world!");
fclose($file);

In this example, the flock() is never called! The warning prevents the execution of potentially harmful code, ensuring issues are caught early during development.

Constraints

The use of #[NoDiscard] comes with some logical constraints:

  • It cannot be applied to functions with a void or never return type, as enforcing usage of a non-existent return value doesn't make sense.
  • It cannot be used on property hooks (getters/setters), as reading a property inherently means you're working with its value. Ignoring it would lead to unnecessary confusion and complexity.

So, what do you think? I personally find the #[NoDiscard] attribute powerful and particularly valuable for library authors. I'm eagerly awaiting PHP 8.5 to incorporate this new feature into my own projects!

you are viewing a single comment's thread
view the rest of the comments
[–] tux0r@feddit.org 1 points 3 days ago (3 children)

The problem is that PHP's normal way of functioning is that return values are optional, even if a function is not declared void. I mean, it is kind of nice that you can tell PHP to please respect function types and throw a suppressable! warning, but I'd honestly prefer Rust's "it won't even compile" approach here.

[–] dominik@chrastecky.dev 3 points 3 days ago (1 children)

Well, that's historical, if PHP was being designed today, I think a lot of the things would look very different. As everything since version 7.x, this is a step in the right direction of making the language modern and safer to use.

Like, this is still PHP, both of these are equally valid:

<?php

function hello(string $name): string {
  return "Hello, {$name}!";
}

function hello($name) {
  return "Hello, $name!";
}

So anything that makes it possible to write a good, clean code is a great addition, IMO.

[–] tux0r@feddit.org 1 points 3 days ago (1 children)

I wish PHP would deprecate (and, subsequently, remove) more of the less clean constructs. Then again, I fondly remember the public outcry when mysql_* was removed.

[–] dominik@chrastecky.dev 2 points 3 days ago

Same, but given how seriously they take BC breaks, I don't really see it happening. Well, at least we have mature tooling to avoid having horrible code in production code-bases.

load more comments (1 replies)