PHP 8.5: New Features and Upgrade Guide

· PHP, Development

Table of contents

PHP 8.5 was released on November 20, 2025, and if you maintain a long-lived PHP codebase (as I do with Magento projects), the question is no longer "what is new?" but "is it time to upgrade, and what will break?". In this post I go through the PHP 8.5 features I will actually use, and the deprecations you should grep for before flipping the version in your Dockerfile.

The pipe operator

The headline feature is the pipe operator |>, which chains callables from left to right without intermediary variables. The official example turns a title into a slug:

$title = ' PHP 8.5 Released ';

$slug = $title
    |> trim(...)
    |> (fn($str) => str_replace(' ', '-', $str))
    |> (fn($str) => str_replace('.', '', $str))
    |> strtolower(...);

// "php-85-released"

I like it for data-massaging code, where nested calls like strtolower(str_replace(...)) read inside-out. Use it for short, linear transformations; if you need three arrow functions on every line, a small named function is still clearer.

Clone with and immutable objects

clone() now accepts an array of property updates, which finally makes the "with-er" pattern painless on readonly classes:

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]);
    }
}

Value objects (prices, addresses, DTOs) are everywhere in e-commerce code, and this removes a lot of constructor-copying boilerplate.

Small additions that add up

  • array_first() and array_last() return the first or last value, or null for an empty array. No more reset()/end() tricks that mutate the internal pointer.
  • The URI extension parses and modifies URIs following RFC 3986 and WHATWG URL standards, with objects such as Uri\Rfc3986\Uri, instead of the quirks of parse_url().
  • #[\NoDiscard] warns when a return value is ignored; cast to (void) to say it is intentional. Handy for methods returning a result object you must check.
  • Fatal errors now include a backtrace, which makes "maximum execution time exceeded" far easier to debug in production logs.
  • Persistent cURL share handles (curl_share_init_persistent()) can reuse connections across requests, useful for code calling the same APIs constantly.

Deprecations to fix first

Deprecations are what turn an upgrade into a bad afternoon, so check these before anything else:

  • The backtick operator (alias of shell_exec()) is deprecated.
  • Non-canonical casts (boolean), (integer), (double) and (binary) are deprecated; use (bool), (int), (float), (string).
  • Using null as an array offset or in array_key_exists() is deprecated; use an empty string.
  • Ending a case with a semicolon instead of a colon is deprecated.
  • __sleep() and __wakeup() are soft-deprecated in favour of __serialize() and __unserialize().
  • The disable_classes INI setting has been removed.
  • New warnings appear when casting NAN, when destructuring non-array values, and when casting floats that cannot be represented as an integer.

Most of these can be found with a quick search. Old third-party modules are the usual offenders, particularly the casts and null offsets.

My upgrade checklist

  1. Read the official PHP 8.5 migration guide.
  2. Check that your framework and every Composer dependency declare support for 8.5 (composer why-not php 8.5 is a quick start).
  3. Run your test suite and static analysis on an 8.5 container with error_reporting = E_ALL so deprecations are visible.
  4. Fix deprecations in your own code first, then update or patch dependencies.
  5. Deploy to staging, watch the logs for a few days, then production.

Conclusion

PHP 8.5 is not a revolution, but the pipe operator, clone with, array_first()/array_last() and better fatal-error backtraces all remove small daily frictions. The upgrade cost is mostly deprecation clean-up, and that is cheap if you start early. If you want a broader view of where the language came from, see my post on the evolution of PHP.

Sources: php.net: PHP 8.5 release announcement, Phoronix: PHP 8.5 Released.