The first alpha version of PHP 8.5 has just been released, and I must confess it has me more excited than recent versions. It’s not just for the technical improvements (which are many), but because PHP 8.5 introduces features that will change the way we write code.
And when I say “change,” I mean the kind of changes that, once you use them, you can’t go back. Like when the null coalescing operator (??) appeared in PHP 7, or arrow functions in PHP 7.4.
The star of the show: The Pipe Operator (|>)
Without a doubt, the pipe operator is generating the most noise, and with good reason. It allows us to chain functions elegantly, passing the result of one function directly to the next.
The problem it solves
How many times have you written this?
$result = trim(strtoupper(str_replace(' ', '-', $input)));
Or the “more readable” version with temporary variables:
$step1 = str_replace(' ', '-', $input);
$step2 = strtoupper($step1);
$result = trim($step2);
The elegant solution in PHP 8.5
With the pipe operator, the same code looks like this:
$result = $input
|> str_replace(' ', '-', ...)
|> strtoupper(...)
|> trim(...);
What’s happening here?
- The value of
$inputis passed as the first parameter tostr_replace() - The result is passed to
strtoupper() - And finally to
trim() - The
...indicates we’re using first-class callables
Practical example: Creating a slug
$title = " Hello World! This is a Test. ";
// Before (nested hell)
$slug = strtolower(
str_replace(['.', '!', '?'], '',
str_replace(' ', '-',
trim($title)
)
)
);
// With pipe operator
$slug = $title
|> trim(...)
|> str_replace(' ', '-', ...)
|> fn($s) => str_replace(['.', '!', '?'], '', $s)
|> strtolower(...);
Important limitations
The pipe operator has some restrictions you should know about:
- Only works with callables that accept one parameter
- The value is always passed as the first parameter
- For multi-parameter functions, you need to use arrow functions
// ❌ Won't work - str_replace needs 3 parameters
$result = $input |> str_replace(' ', '-', ...);
// ✅ Correct - using arrow function
$result = $input |> fn($s) => str_replace(' ', '-', $s);
#[\NoDiscard]: Goodbye to Silent Errors
This is another feature I find brilliant. The #[\NoDiscard] attribute allows marking functions whose return value should not be ignored.
The problem
function processPayment($amount): PaymentResult {
// ... processing logic
return new PaymentResult($success, $errorMessage);
}
// ❌ Silent error - we ignore the result
processPayment(100);
// ✅ Correct - we use the result
$result = processPayment(100);
if (!$result->success) {
handleError($result->errorMessage);
}
The solution
#[\NoDiscard]
function processPayment($amount): PaymentResult {
// ... processing logic
return new PaymentResult($success, $errorMessage);
}
// Now PHP will emit a WARNING if you ignore the result
processPayment(100); // Warning: The return value should be used
// You can intentionally suppress with (void)
(void) processPayment(100); // OK - intentionally ignored
Custom message
#[\NoDiscard("Payment results must be checked for errors")]
function processPayment($amount): PaymentResult {
// ...
}
Core functions with NoDiscard
PHP 8.5 already includes #[\NoDiscard] in critical functions like:
flock()- Ignoring its result can cause concurrency problemsDateTimeImmutablemethods - Return new instances, don’t modify the original
Final Property Promotion
PHP 8.5 allows using final directly in constructor property promotion:
class User {
public function __construct(
public readonly string $name,
public final string $email, // ✅ New in PHP 8.5
) {}
}
This prevents child classes from overriding the $email property.
Static Closures in Constant Expressions
A technical but very useful feature for library authors:
class Configuration {
public const VALIDATOR = static function(string $value): bool {
return strlen($value) > 0;
};
public const TRANSFORMER = static function(string $value): string {
return strtoupper($value);
};
}
New Array Functions
PHP 8.5 adds two functions we’ve been waiting for:
$numbers = [1, 2, 3, 4, 5];
$first = array_first($numbers); // 1
$last = array_last($numbers); // 5
// They also work with callbacks
$first_even = array_first($numbers, fn($n) => $n % 2 === 0); // 2
Extension Improvements
The alpha 1 includes significant improvements in many extensions:
cURL
- New constants
CURLFOLLOW_ALL,CURLFOLLOW_OBEYCODE curl_multi_get_handles()function- Support for
CURLINFO_USED_PROXY
DOM
Dom\Element::$outerHTMLDom\Element::insertAdjacentHTML()- New
$childrenproperty for ParentNode
MySQLi
- New
mysqlnd.collect_memory_statisticsoption
PDO
- Support for iterables in
PDO::pgsqlCopyFromArray - New constants in PDO_SQLite
CLI Improvements
A small but useful improvement:
# New flag to see only changed configurations
php --ini=diff
Release Information
Version: 8.5.0alpha1 Release date: QA version (not for production) Scheduled GA: November 20, 2025 Branch status: Active development
How to Try PHP 8.5
Docker (recommended)
# PHP CLI
docker pull php:8.5.0alpha1-cli
# PHP with Apache
docker pull php:8.5.0alpha1-apache
# PHP-FPM
docker pull php:8.5.0alpha1-fpm
Compiling from Source
git clone https://github.com/php/php-src.git --depth 1 --branch php-8.5.0alpha1
cd php-src
./buildconf
./configure --enable-debug
make -j$(nproc)
Windows Binaries
Available for download from windows.php.net in both Thread-Safe and Non-Thread-Safe versions.
My Experience with the Alpha
I’ve been playing with the alpha for a few weeks, and here are my impressions:
The pipe operator is addictive
Once you start using it, it’s hard to stop. It’s especially useful for:
- Data transformations
- Validation and sanitization
- String processing
- Functional operations
NoDiscard is gold for libraries
As a library author, #[\NoDiscard] is exactly what I needed. Finally I can force users to properly handle critical return values.
The stability is surprising
For an alpha, PHP 8.5 feels quite stable. I’ve run some of my Laravel applications without major issues.
Compatibility Considerations
Existing code
The pipe operator uses new syntax, so your existing code will continue to work without changes.
Development tools
- PHPStan and Psalm are already working on support for new features
- PHP-CS-Fixer and PHP CodeSniffer will need updates
- IDEs like PhpStorm will likely add support in upcoming versions
The Future Looks Promising
PHP 8.5 marks a turning point. The pipe operator is not just syntactic sugar - it’s a fundamentally different way of writing PHP code. More functional, more readable, more expressive.
And #[\NoDiscard] will make many libraries more robust and secure.
Next Steps
- Now: Experiment with the alpha in a development environment
- September 2025: Betas will start arriving
- November 2025: Final release
Additional Resources
- PHP 8.5 Release Information - Official release information
- PHP 8.5 RFCs - All approved RFCs
- Pipe Operator RFC - Technical documentation of the pipe operator
- NoDiscard RFC - NoDiscard attribute documentation
- PHP 8.5 Features Overview - Complete feature overview
- Pipe Operator Tutorial - Detailed pipe operator tutorial
Conclusion
PHP 8.5 is not just another update - it’s a significant evolution of the language. The pipe operator will change how we structure our code, and #[\NoDiscard] will make it more robust.
Have you tried the alpha yet? What do you think of the pipe operator? I’d love to know your experience and use cases.
Did you find this article helpful? Share it with other PHP developers who might be interested in PHP 8.5’s new features. And if you have any questions or experiences to share, don’t hesitate to contact me.





