PHP 8.5 will be released next month on November 20th, 2025, and will feature the Pipe operator, a new URI extension, new array_first() and array_last() functions, and more:
- The Pipe Operator
- Native array_first() and array_last() Functions
- A New URI Extension
- Retrieve the Currently Executing Closure
- PHP Fatal Error Backtraces
- INI Diff Option
- And more...
See the PHP 8.5 RFC page for a complete list.
The Pipe Operator
The Pipe Operator is an exciting prospect for PHP developers wanting to chain multiple callables together, passing a value through them from left to right in a native way:
// Using the pipe operator in PHP 8.5
$result = "Hello World"
|> htmlentities(...)
|> str_split(...)
|> fn($x) => array_map(strtoupper(...), $x)
|> fn($x) => array_filter($x, fn($v) => $v != 'O');
Native array_first() and array_last() Functions
PHP 8.5 will include array_first() and array_last() functions. While on the surface, these functions might not seem like a huge deal (and the PHP community has userland implementations and polyfills), these functions are long overdue as native functions in the PHP language.
These functions complement the already provided array key methods merged in PHP 7.3:
In PHP 7.3, we got array_key_first() and array_key_last() to get the first and last keys from an array. What we don't have yet is a way to get the first and last values of an array. This is harder than you may think because:
- The array keys are not necessarily integers, not necessarily starting with 0, etc...
- Existing “tricks” like reset() and end() are semantically the wrong approach because they modify the “internal iterator” of the array. Furthermore, it also does not work properly on all types of expressions (e.g. an array returned from a function / plain array can cause a notice due to the by-ref argument).
- Using $array[array_key_first($array)] is cumbersome
We have a more detailed post on array_first() and array_last() if you want to dive deeper, but here are some examples of the function signatures and how they work:
// Function signatures
function array_first(array $array): mixed {}
function array_last(array $array): mixed {}
// Examples
array_first(["single element"]); // "single element"
array_last(["single element"]); // "single element"
array_first([]); // NULL
array_last([]); // NULL
array_first([1 => 'a', 0 => 'b', 3 => 'c', 2 => 'd']); // 'a'
array_last([1 => 'a', 0 => 'b', 3 => 'c', 2 => 'd']); // 'd'
$str = "hello";
array_first([&$str, false]); // "hello" (no ref)
array_last([false, &$str]); // "hello" (no ref)
A New URI Extension
PHP 8.5 introduces a new URI extension, which is a standards-compliant parser "for both RFC 3986 and the WHATWG URL standard as an always-available part of its standard library within a new 'URI' extension." The RFC has plenty of examples, but here's one from the PHP foundation announcement post showcasing the RFC 3986 Uri class:
use Uri\Rfc3986\Uri;
$url = new Uri('HTTPS://thephp.foundation:443/sp%6Fnsor/');
$defaultPortForScheme = match ($url->getScheme()) {
'http' => 80,
'https' => 443,
'ssh' => 22,
default => null,
};
// Remove default ports from URLs.
if ($url->getPort() === $defaultPortForScheme) {
$url = $url->withPort(null);
}
// Getters normalize the URL by default. The `Raw`
// variants return the input unchanged.
echo $url->toString(), PHP_EOL;
// Prints: https://thephp.foundation/sponsor/
echo $url->toRawString(), PHP_EOL;
// Prints: HTTPS://thephp.foundation/sp%6Fnsor/
Retrieve the Currently Executing Closure
PHP 8.5 will support recursion in Closures by fetching the currently executing Closure (hat tip to Alexandre Daubois). As pointed out in the rfc:closure_self_reference RFC, the current workaround is binding a variable reference into a closure. PHP 8.5 provides the static Closure::getCurrent() to get the currently running closure:
$fibonacci = function (int $n) {
if (0 === $n || 1 === $n) {
return $n;
}
$fn = Closure::getCurrent();
return $fn($n - 1) + $fn($n - 2);
};
echo $fibonacci(10) . "\n";
PHP Fatal Error Backtraces
A new fatal_error_backtraces setting can control whether a backtrace is shown for fatal errors. The fatal_error_backtraces setting will default to 1 in PHP 8.5—you don't have to configure anything to get these backtraces (though you can disable them if you want). Fatal errors without backtraces in today's stable PHP versions (i.e., PHP 8.4) might include parse errors (syntax errors), duplicate functions or classes, infinite loops with a max execution time, etc.
Fatal error: Cannot redeclare class B (previously declared in /srv/app/index.php:11) in /srv/app/b.php on line 3
Stack trace:
#0 /srv/app/index.php(6): require()
#1 /srv/app/index.php(21): A->loadClassB()
#2 {main}
INI Diff Options
PHP 8.5 introduces a INI diff option for the php --ini flag that makes it easy to identify changed INI values in your configuration. The --ini flag is helpful to show the loaded php.ini configuration file, as well as additional .ini files parsed:
$ php --ini=diff
Non-default INI settings:
allow_url_include: "0" -> ""
auto_append_file: (none) -> ""
auto_prepend_file: (none) -> ""
display_errors: "1" -> ""
display_startup_errors: "1" -> ""
enable_dl: "1" -> ""
error_reporting: (none) -> "22527"
...
The Schedule
The remaining schedule for PHP 8.5's release includes two more release candidates and then the GA release on November 20th:
| Jul 03 2025 | Alpha 1 |
| Jul 17 2025 | Alpha 2 |
| Jul 31 2025 | Alpha 3 (skipped) |
| Jul 31 2025 | Alpha 4 |
| Aug 12 2025 | Feature Freeze |
| Aug 14 2025 | Beta 1 |
| Aug 28 2025 | Beta 2 |
| Sep 11 2025 | Beta 3 |
| Sep 25 2025 | RC1 |
| Oct 09 2025 | RC2 |
| Oct 23 2025 | RC3 |
| Nov 06 2025 | RC4 |
| Nov 20 2025 | GA |
| The release schedule is outlined on the PHP 8.5 Preparation Tasks page. |
Learn more
There are many more updates coming to PHP 8.5 - you can see the full list of RFCs coming to PHP 8.5 in November. The PHP 8.5 preparation tasks page has the release timeline of the upcoming releases. To start using PHP 8.5 now, you can download the PHP 8.5 RC source from the downloads page. Lastly, you can see a list of PHP 8.5 deprecations if you want to get a head start on upgrades 😎.
.png)
