News

PHP 8.5 is released with the pipe operator, URI extension, new array functions, and more

Published
PHP 8.5 is released with the pipe operator, URI extension, new array functions, and more image

The PHP team has released PHP v8.5 with the Pipe operator, a URI extension, array_first() and array_last() functions, an INI diff flag, 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";

Support for Closures in Constant Expressions

PHP 8.5 introduces support for closures in constant expressions, making it possible to define a default attribute value as a Closure, among other use-cases:

function my_array_filter(
array $array,
Closure $callback = static function ($item) { return !empty($item); },
) {
$result = [];
 
foreach ($array as $item) {
if ($callback($item)) {
$result[] = $item;
}
}
 
return $result;
}
 
my_array_filter([
0, 1, 2,
'', 'foo', 'bar',
]); // [1, 2, "foo", "bar"]

See our detailed post on this feature to learn more.

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"
...

Learn More

To get up to speed on these new features, check out the PHP 8.5 Release Announcement page for examples before/after PHP 8.5. Be sure to check out the deprecations and backward compatibility breaks.

The following list of additional resources has everything you need to learn more about this release:

  • The UPGRADING document includes backward-incompatible changes, new features, and everything else you'll need to familiarize yourself with changes in PHP 8.5
  • The NEWS document has detailed notes about each release
  • The PHP 8.5 preparation tasks page has the release timeline of the upcoming releases
  • You can download PHP 8.5 source from the downloads page
Paul Redmond photo

Staff writer at Laravel News. Full stack web developer and author.

Filed in

Sponsored

serpapi logo
SerpApi

The Web Search API for Your LLM and AI Applications

Visit SerpApi

The latest

View all →
CPX: The Composer Package Executor for PHP image

CPX: The Composer Package Executor for PHP

Read article
Laravel AI SDK Adds Human-in-the-Loop Tool Approval image

Laravel AI SDK Adds Human-in-the-Loop Tool Approval

Read article
Pest 5 Released With Test Impact Analysis, Agent Verification, and Evals image

Pest 5 Released With Test Impact Analysis, Agent Verification, and Evals

Read article
Queue-SQL: Run Mass Deletes and Updates Across Parallel Queue Jobs image

Queue-SQL: Run Mass Deletes and Updates Across Parallel Queue Jobs

Read article
Blade Formatting in Laravel Pint image

Blade Formatting in Laravel Pint

Read article
Inertia DevTools Is Now on the Chrome Web Store image

Inertia DevTools Is Now on the Chrome Web Store

Read article