1. Home
  2. /Blog
  3. /PHP 8.5: 3 Features That Make Your Code Cleaner
2026-02-233 min readLoading views...Backend

PHP 8.5: 3 Features That Make Your Code Cleaner

The pipe operator, property hooks, and #[NoDiscard] in PHP 8.5 help you write clearer, safer code—with less nesting and less boilerplate.

PHPPHP 8.5BackendPipe OperatorProperty HooksNoDiscard

PHP 8.5: 3 Features That Make Your Code Cleaner

2026-02-233 min readBackend
Table of contents
1. The pipe operator (`|>`)2. Property hooks (get/set)3. The `#[NoDiscard]` attributeSummary

PHP isn’t “old”—it’s evolving. With PHP 8.5 (released November 2025), you get language features that make everyday code easier to read and maintain. Here are three that actually change how you write: the pipe operator, property hooks, and the #[NoDiscard] attribute.


1. The pipe operator (|>)

The problem: Deeply nested function calls are hard to read. Who wants to count brackets?

php
// Nested: inside-out, easy to misread
$slug = strtolower(str_replace('.', '', str_replace(' ', '-', trim($title))));

The fix: The pipe operator (|>) passes the value on the left into the callable on the right. You read it top to bottom, like a pipeline.

php
$title = ' PHP 8.5 Released ';
$slug = $title
|> trim(...)
|> (fn(string $s) => str_replace(' ', '-', $s))
|> (fn(string $s) => str_replace('.', '', $s))
|> strtolower(...);
// $slug === 'php-85-released'

For built-in functions like trim and strtolower, use ... so PHP treats them as single-argument callables. For custom logic, use an arrow function. Each step takes one input and returns the next value—no nesting.

Another example: normalizing user input before validation.

php
$raw = " JOHN@EXAMPLE.COM ";
$email = $raw
|> trim(...)
|> strtolower(...);
// Ready for validate($email)

2. Property hooks (get/set)

The problem: You end up with boring getters and setters just to validate or transform a value. Lots of boilerplate for one field.

The fix: Property hooks (PHP 8.4, part of the 8.5 toolset) let you define get and set behavior directly on the property. No separate methods.

Example: validated email

php
class User
{
public string $email {
set {
if (!filter_var($value, FILTER_VALIDATE_EMAIL)) {
throw new InvalidArgumentException('Invalid email');
}
$this->email = strtolower($value);
}
}
}
$user = new User();
$user->email = 'Jane@Example.COM'; // Stored as 'jane@example.com'
$user->email = 'not-an-email'; // Throws InvalidArgumentException

Example: virtual (computed) property

When the value isn’t stored but derived, use a virtual property with only a get hook:

php
class Rectangle
{
public function __construct(
public int $height,
public int $width,
) {}
public int $area {
get => $this->height * $this->width;
}
}
$r = new Rectangle(4, 5);
echo $r->area; // 20

Shorthand: For a simple transform in set, you can use an arrow expression:

php
public string $name {
set => strtolower($value);
}

You keep a single, clear property while moving validation and formatting into the declaration. Fewer lines, same behavior.


3. The #[NoDiscard] attribute

The problem: Some functions communicate success or failure via their return value. If the caller ignores it, bugs can hide—e.g. a failed lock or a failed DateTimeImmutable::modify() that you never check.

The fix: The Marking return values as important RFC adds the #[\NoDiscard] attribute. If the return value is ignored, PHP emits a warning (so you don’t silently drop important results).

Using it in your own code:

php
#[\NoDiscard]
public function generateToken(): string
{
$token = bin2hex(random_bytes(32));
$this->storeToken($token);
return $token;
}
// Later:
$this->generateToken(); // Warning: return value of generateToken() must be used
$token = $this->generateToken(); // OK

Optional message: You can explain why the value matters:

php
#[\NoDiscard('Token must be shown to the user or stored.')]
public function generateToken(): string { ... }

When you intentionally ignore the return value: Cast to (void) to silence the warning:

php
(void) $this->generateToken(); // Explicit: "I know I'm discarding this."

PHP 8.5 also applies #[\NoDiscard] to several built-ins (e.g. some DateTimeImmutable::set* methods and flock()), so ignoring their return values will trigger a warning and nudge you toward safer code.


Summary

FeatureWhat it doesUse it when
Pipe operatorChains operations left-to-rightTransforming data step by step
Property hooksget/set logic on the propertyValidation, normalization, computed values
NoDiscardWarns when return value is ignoredAPIs that signal failure via return

PHP 8.5 is about writing clearer, more predictable code—less nesting, less boilerplate, and fewer silent mistakes. If you’re still on 8.4 or earlier, these three features are good reasons to plan an upgrade.

References

  • PHP 8.5 Release Announcement
  • Pipe operator v3 (RFC)
  • Property Hooks (PHP Manual)
  • Marking return values as important / NoDiscard (RFC)

Comments

No comments yet

Loading comments...

Table of contents
1. The pipe operator (`|>`)2. Property hooks (get/set)3. The `#[NoDiscard]` attributeSummary
or search for other articles
Previous

Laravel 13: Release Date, New Features, and How to Prepare (2026)

2026-02-23Backend
No next post

Let's Talk.

LinkedInGitHubTwitter

© 2024 idnasirasira.

Designed & Engineered with ♥ in Jakarta.