PHP 8.5 was released on 20 November 2025. As with the previous lessons, this code needs PHP 8.5 or newer and cannot run on older versions (including the PHP 8.2 server used to test this course). The examples follow the official release notes at php.net/releases/8.5.
The pipe operator |>
The pipe operator takes the value on the left and passes it to the callable on the right. It lets you read a chain of steps from left to right, without nesting calls or using temporary variables.
<?php
$title = " PHP 8.5 Is Here. ";
$slug = $title
|> trim(...)
|> (fn(string $s) => str_replace(" ", "-", $s))
|> (fn(string $s) => str_replace(".", "", $s))
|> strtolower(...);
echo $slug; // php-85-is-here
Each step receives the result of the step before it. First-class callables (trim(...)) and arrow functions both work. Arrow functions are wrapped in brackets.
The same without the pipe operator:
<?php
$title = " PHP 8.5 Is Here. ";
$slug = strtolower(str_replace(".", "", str_replace(" ", "-", trim($title))));
echo $slug;
php-85-is-here
The nested version reads inside out. The piped version reads in the order things happen.
array_first() and array_last()
Two functions return the first or last value of an array, or null if the array is empty.
<?php
$events = ["start", "middle", "end"];
echo array_first($events); // start
echo array_last($events); // end
Older code used $arr[array_key_first($arr)] or end($arr).
<?php
function firstValue(array $items): mixed
{
return $items === [] ? null : $items[array_key_first($items)];
}
function lastValue(array $items): mixed
{
return $items === [] ? null : $items[array_key_last($items)];
}
echo firstValue(["start", "middle", "end"]) . " " . lastValue(["start", "middle", "end"]);
start end
clone with
PHP 8.5 lets clone accept new property values, which makes “with” methods on readonly classes much shorter.
<?php
readonly class Color
{
public function __construct(
public int $red,
public int $green,
public int $blue,
public int $alpha = 255,
) {}
public function withAlpha(int $alpha): self
{
return clone($this, ["alpha" => $alpha]);
}
}
$blue = new Color(79, 91, 147);
$transparent = $blue->withAlpha(128);
The #[\NoDiscard] attribute
Warns when a function’s return value is ignored. It helps with functions where the result must be checked.
<?php
#[\NoDiscard]
function getPhpVersion(): string
{
return "PHP 8.5";
}
getPhpVersion(); // Warning: the return value should be used
Closures in constant expressions
Static closures and first-class callables can be used where constant expressions are allowed, for example in attribute arguments and constants.
The URI extension
A new always-available extension parses and normalises URIs following RFC 3986 and the WHATWG URL standard.
<?php
use Uri\Rfc3986\Uri;
$uri = new Uri("https://php.net/releases/8.5/en.php");
var_dump($uri->getHost()); // string(7) "php.net"
Other changes
- A persistent cURL share handle (
curl_share_init_persistent()). - Various deprecations and smaller improvements. Read the official migration guide before upgrading a large project.
What to do with this
- Learn the idea of each feature, so you recognise it in code.
- Use features from versions your production server runs.
- Keep an eye on php.net/supported-versions.php to see which versions still receive fixes.