What's new in PHP 8.5

  • avatar
  • 166 Views
  • 6 mins read

PHP 8.5 lands with a pack of features that smooth out daily development, remove long-standing friction points, and make functional patterns far easier to write. It feels like a release focused on practical wins: cleaner code, stronger introspection tools, safer configuration defaults, and more helpful debugging. Let's walk through the most interesting additions.

The Pipe Operator

One of the most talked about additions is the new pipe operator. The operator evaluates left to right, passing the previous expression's value into the next function or closure.

Before PHP 8.5, you might write something like this:

$input = ' Some kind of string. ';

$output = strtolower(
str_replace(['.', '/'], '',
str_replace(' ', '-',
trim($input)
)
)
);

With the pipe operator, the same logic becomes far clearer:

$input = ' Some kind of string. ';

$output = $input
|> trim(...)
|> (fn ($string) => str_replace(' ', '-', $string))
|> (fn ($string) => str_replace(['.', '/'], '', $string))
|> strtolower(...);

You can also use pipes to chain arbitrary callables, which helps when modeling functional flows without a heavyweight collection class:

$numberOfAdmins = $userRepository->fetchUsers()
|> (fn ($list) => array_filter($list, fn (User $u): bool => $u->isAdmin()))
|> count(...);

This cuts down on nested calls and makes linear transformations clearer.

New array_first and array_last functions

Two new functions, array_first() and array_last(), return the first and last values of an array. This avoids using array_key_first() combined with extra indexing.

Basic usage looks like this:

$single = ['single element'];
var_dump(array_first($single)); // string 'single element'
var_dump(array_last($single)); // string 'single element'

$empty = [];
var_dump(array_first($empty)); // null
var_dump(array_last($empty)); // null

$mixed = [1 => 'a', 0 => 'b', 3 => 'c', 2 => 'd'];
var_dump(array_first($mixed)); // 'a'
var_dump(array_last($mixed)); // 'd'

Note that these return the value and not the key. They also handle empty arrays by returning null so you can safely coalesce or test the result without extra checks.

Clone with properties

Readonly properties introduced a quirky side effect: cloning objects while adjusting just one property became painful. Many developers had to resort to reflection or reconstruct objects manually. PHP 8.5 fixes this by extending clone into a construct that accepts a second argument: an array of property names and updated values.

The signature effectively becomes:

clone(object $object, array $withProperties = []): object

An example will look like as following:

final class Book
{
public function __construct(
public string $title,
public string $description,
) {}

public function withTitle(string $title): self
{
return clone($this, [
'title' => $title,
]);
}
}

$copies = array_map(clone(...), $listOfBooks);

This is a big improvement for immutability patterns and object hydration.

New URI extension and parsing tools

PHP 8.5 ships a new always-available URI extension covering RFC 3986 and the WHATWG standard. It normalizes URLs by default but lets you retrieve the raw form when needed.

Example using the RFC 3986 Uri class:

use Uri\\Rfc3986\\Uri;

$url = new Uri('HTTPS://hibit.dev:443');

$uri->getHost();
$uri->getScheme();
$uri->getPort();
$url->toString(); // https://hibit.dev:443
$url->toRawString(); // HTTPS://hibit.dev:443

You get predictable normalization, editable components, and clearer handling of ports and encodings.

Max memory limit

The max_memory_limit acts as a hard cap. Once set, any attempt to raise memory_limit above this ceiling will trigger a warning and reset it to the maximum allowed. It cannot be changed at runtime since it’s an INI_SYSTEM directive, making it perfect for administrators who want tighter control over memory use across all scripts.

ini_get('max_memory_limit'); // "256M"
ini_get('memory_limit'); // "128M"

ini_set('memory_limit', '156M'); // Allowed, lower than max_memory_limit 256M
ini_set('memory_limit', '256M'); // Allowed, equal to max_memory_limit 256M
ini_set('memory_limit', '300M'); // Warning, set to max_memory_limit instead
ini_set('memory_limit', '-1'); // Warning, cannot remove restriction

This new directive gives developers and system administrators a clear safety net, preventing runaway scripts from consuming excessive memory and stabilizing resource usage across environments.

Internationalization enhancements

PHP 8.5 includes several i18n improvements that help apps that must handle multiple locales and scripts.

One addition is a helper to test layout direction:

locale_is_right_to_left('ar_EG'); // true for Arabic Egypt

There is also a Locale class method Locale::isRightToLeft and a new IntlListFormatter class for locale aware list formatting. These additions make it easier to build UIs and text output that respect language conventions such as list separators and right to left behavior.

Improved debugging for fatal errors

Fatal errors now include backtraces by default, controlled by the fatal_error_backtraces INI directive. That change makes it far easier to track the origin of hard failures in production.

A fatal error message now prints a stack trace similar to regular exceptions. In practice this shortens the time it takes to find a cause when you see a runtime crash in logs and you do not have an interactive debugger attached.

 Join Our Monthly Newsletter

Get the latest news and popular articles to your inbox every month

We never send SPAM nor unsolicited emails

0 Comments

Leave a Reply

Your email address will not be published.

Replying to the message: View original

Hey visitor! Unlock access to featured articles, remove ads and much more - it's free.