PHP 8.6: New Features, Deprecations and Upgrade Plan
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()andJsonExceptionmessages 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()andisWritable(), plusReflectionParameter::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
returnstatement inside afinallyblock. - 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()oris_subclass_of()with a string first argument while$allow_stringis false. - Using
let,isor_as a class, function or constant name,namespaceas a class constant name, or naming a functionreadonly. - In extensions: mbstring's regex functions (
mb_ereg*), because the Oniguruma library behind them is no longer maintained, andmysqli_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
- 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.
- 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.
- 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.
- Upgrade staging, then production, and keep the previous PHP version installed on the server so a rollback is one config change.
- 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.