On November 20, 2025, the PHP development team officially released PHP 8.5, marking a significant step forward in the language’s evolution. This version brings a suite of new features designed to improve expressiveness, readability, performance, and safety.
Key Features and Improvements
- URI Extension
- Pipe Operator
- Clone With
- #[\NoDiscard] Attribute
- Closures in Constant Expressions
- Recusion in Closures
- New Array functions
array_first()andarray_last()
– New URI Extension
A major addition in PHP 8.5 is the built-in URI extension, which provides a robust API to parse, normalize, and manipulate URIs following RFC 3986 and WHATWG URL standards.
This extension is now ships natively, providing a safer, more standard-compliant way to work with URLs in your code.
Usage looks like:
use Uri\Rfc3986\Uri;
$uri = new Uri('https://example.com/path?query=php');
echo $uri->getHost(); // "example.com"
echo $uri->getScheme(); // "https"
– Pipe Expression
The pipe operator (|>). This operator makes it much easier to compose chained function calls in a left-to-right, readable manner, eliminating deeply nested calls and minimizing the use of intermediate variables.
Previously:
$output = strtolower(
str_replace(['.', '/', '…'], '',
str_replace(' ', '-',
trim($input)
)
)
);
With the pipe operator:
– #[\NoDiscard] Attribute
Most of the time we call functions directly without consuming it’s return value. In PHP 8.5 when marking a function with the #[\NoDiscard] attribute PHP will check whether the returned value is consumed and emit a warning if it is not:
#[NoDiscard("you must use this return value.")]
function helloWorld(): string {
return 'Hello World';
}
helloWorld();
// Warning:
// The return value of function helloWorld() is expected to be consumed,
// you must use this return value.
The associated (void) cast can be used to indicate that a value is intentionally unused.
(void) helloWorld(); // explicitly discards without warning
– Closures in Constant Expressions
PHP 8.5 now allows static closures and first-class callables to be used inside constant expressions — for instance, as attribute arguments or default values.
#[SomeAttribute(static function (Container $c): bool {
return $c->get(Service::class) !== null;
})]
class MyClass { … }
– Recursion in Closures
PHP 8.5 provides the static Closure::getCurrent() method that refers to the currently execution closure, which is helpful when the need to do recursive call inside the closure:
$countdown = function (int $number) {
if ($number <= 0) {
echo "Done\n";
return;
}
echo $number . "\n";
$f = Closure::getCurrent();
$f($number - 1);
};
$countdown(10);
– New array_first and array_last functions
New additions to the array functions in PHP 7.3 array_key_first() and array_key_last() to retrieve the first and last array keys. Now with PHP 8.5 includes built-in array_first() and array_last() functions to retrieve the first and last array values.
$arr = ['red', 'blue', 'green', 'black']; $first = array_first($arr); // red $last = array_last($arr); // black
– Persistent cURL Share Handles
Through curl_share_init_persistent(), PHP 8.5 allows cURL share handles to persist across requests.
Example from php.net:
$sh = curl_share_init_persistent([
CURL_LOCK_DATA_DNS,
CURL_LOCK_DATA_CONNECT,
]);
$ch = curl_init('https://php.net/');
curl_setopt($ch, CURLOPT_SHARE, $sh);
// This may now reuse the connection from an earlier SAPI request
curl_exec($ch);
– Fatal Error Backtraces
Previously, fatal errors (e.g., timing out, memory exhaustion) would generally give only a message. With PHP 8.5, fatal errors now include backtraces, giving more context about where and how they occurred.
Fatal error: ..... in helpers.php on line 200 Stack trace: #0 helpers.php(200): upgrade() #1 helpers.php(210): checkPerms() #2 helpers.php(210): getPerms()
– Other Notable Improvements
Beyond the headline features, PHP 8.5 brings several smaller but impactful enhancements. These include:
-
Asymmetric visibility for static properties, allowing more control over who can read/write static props. PHP.net
-
Constructor property promotion for final properties, meaning you can now declare
finalproperties directly in the constructor parameters. -
Attributes on constants, i.e., non-class compile-time constants can now have PHP attributes.
-
A new
#[\DelayedTargetValidation]attribute: this delays attribute target validation to runtime rather than compile time, useful for backward compatibility when using attributes on “invalid” targets. -
Overridable
#[\Override]on properties, not just methods. -
New functions:
get_error_handler()andget_exception_handler()to introspect current handlers.


