PHP 8.6: New Features, Deprecations and Upgrade Plan

· PHP, Development

Table of contents

PHP 8.6 is due on 19 November 2026. The php.net news archive lists the last release candidate on 12 November with general availability planned a week later, so the feature set is frozen and it is a good moment to look at what actually changes. I went through the official UPGRADING notes rather than the many preview articles, because some of them list features that did not make it into the release. Here is what matters for Laravel and Magento projects, and how I plan the upgrade.

Partial function application, the headline feature

The big language change is partial function application (RFC v2). You call a function with some arguments filled in and a ? placeholder for the ones you want to supply later, and PHP gives you back a closure instead of calling it:

// Before: a closure just to fix two arguments
$slugs = array_map(fn ($s) => str_replace(' ', '-', $s), $titles);

// PHP 8.6: the ? placeholder becomes the closure's parameter
$slugs = array_map(str_replace(' ', '-', ?), $titles);

A ? stands for exactly one argument, and ... stands for "all the remaining arguments", which extends the first-class callable syntax (strlen(...)) that arrived in PHP 8.1. It works for functions, methods and static methods.

Where I expect to use it: collection pipelines, array_map/array_filter callbacks and event listeners, where today we write short arrow functions whose only job is to fix one or two arguments. It will not replace closures that hold real logic, and I would not rewrite working code just to use it.

Smaller language changes worth knowing

  • Readonly properties can declare default values (RFC), which removes a lot of constructor boilerplate in value objects and DTOs.
  • #[\Override] works on class constants, enum cases included, so a typo in an overridden constant name is now caught like it is for methods.
  • Enums can define __debugInfo(), handy for cleaner dumps.
  • Objects stored in constants can be mutated directly with CONSTANT->prop = $value.
  • JSON errors now say where they happened: json_last_error_msg() and JsonException messages include the error location. Small, but it saves time when an API payload is malformed.

New classes and functions

The date extension gains a Time\Duration class (RFC) for representing lengths of time, and there is a new native polling API for watching several streams at once (RFC), mostly interesting for long-running workers and socket code. Other additions I noted:

  • mysqli::quote_string() / mysqli_quote_string().
  • ReflectionProperty::isReadable() and isWritable(), plus ReflectionParameter::getDocComment(), which framework and tooling authors will appreciate.
  • grapheme_strrev() in intl, and TLS session resumption options for OpenSSL streams.

One correction to the previews circulating: several articles announce a built-in clamp() function, but it is not listed in the PHP 8.6 UPGRADING notes, so don't plan code around it.

Deprecations to fix before you upgrade

Deprecations only emit notices in 8.6, but they will become errors in a later major version, and a noisy log hides real problems. The ones most likely to show up in application code:

  • A return statement inside a finally block.
  • Returning a value from __construct() or __destruct(), or making them generators.
  • Passing a third argument to define() (the old case-insensitive flag).
  • Calling is_a() or is_subclass_of() with a string first argument while $allow_string is false.
  • Using let, is or _ as a class, function or constant name, namespace as a class constant name, or naming a function readonly.
  • In extensions: mbstring's regex functions (mb_ereg*), because the Oniguruma library behind them is no longer maintained, and mysqli_get_charset().

The mb_ereg one deserves a search in older Magento modules and legacy code: replace those calls with preg_* functions and the u modifier.

My upgrade plan for Laravel and Magento projects

  1. Read the backward-incompatible section first. It is longer than usual in 8.6 (DOM, Intl, Session, Standard…). Ten minutes with it beats a day of debugging.
  2. Run the test suite on 8.6 in CI alongside your current version, with deprecations reported. Add a matrix entry rather than switching the whole pipeline.
  3. Wait for your framework and extensions. Check that your Laravel version, Magento release and compiled extensions (Redis, Imagick, Xdebug…) officially support 8.6. Magento in particular only supports specific PHP versions per release line.
  4. Upgrade staging, then production, and keep the previous PHP version installed on the server so a rollback is one config change.
  5. Let a patch release or two pass on critical projects. 8.6.0 is solid after a long RC phase, but 8.6.1 or 8.6.2 usually picks up the first round of fixes.

Remember that a new version is also about security support: PHP 8.6 extends the runway for projects still on older branches, as I described in my PHP 8.2 end-of-life upgrade plan. And whatever branch you run, stay on the latest patch: the fixes for the critical RCE vulnerabilities I covered in this PHP security update post shipped in 8.6's release candidates as well.

Conclusion

PHP 8.6 is not a revolution, but partial function application will quietly change how we write callbacks, readonly defaults and #[\Override] on constants remove small annoyances, and the deprecation list is a useful cleanup checklist. Start testing now on a branch; by the time your framework officially supports it, the upgrade should be a non-event. Your IDE is probably ready already: PhpStorm 2026.3 shipped PHP 8.6 support.