PHP 8.6 Preview: New Features Tested on RC3, and the PHP 8.5 Syntax WordPress and Magento Code Can Use Now

On a cool porcelain ground, the official PHP logo sits on a white card at the top right. A release candidate card at the top left shows a flask tile and reads PHP 8.6.0RC3, with chips for Test only and GA 19 Nov 2026. Below it, a code card labelled New in 8.6 shows two lines: a pipe step str_replace with a question mark placeholder, and clamp(15, 0, 10) returning int(10). Under that, a rose notice strip reads Deprecated: spl_object_hash(). A dashed arrow with a clock leads right to a production card with a server tile reading PHP 8.5 with a tick, above the WordPress logo labelled WordPress and a storefront icon labelled Magento, and the line Only what your stack supports.

In short: PHP 8.6 is scheduled for 19 November 2026, and its release candidates are for testing only. Use a PHP version your complete stack supports: WordPress core supports 8.5 from 6.9, Magento 2.4.9 supports only 8.5, and WooCommerce lists 8.3 or later and documents testing through 8.4.

Everything below was checked against the third release candidate, 8.6.0RC3, and every snippet was run on it. Nothing here describes a released version: features can still change before general availability.

The few code snippets in this article are short examples for learning, provided as is and without warranty of any kind, and you use them entirely at your own risk. PHP 8.6 is a test release: try every snippet and check on your own machine or a staging copy first, never on a live site, store or database, and take a full backup before you change the PHP version of any server. iLogr accepts no responsibility for any loss, damage or other problem arising from their use.

When is PHP 8.6 released?

General availability is scheduled for 19 November 2026[1]. The soft feature freeze was on 13 August and the hard freeze on 22 September. RC2 shipped on 24 September and RC3 on 8 October; RC4 is planned for 22 October and RC5 for 5 November[1][2]. There was no released RC1: the code tagged for it carried the wrong API numbers, so the first candidate was published as RC2[3]. Each announcement says the same thing: "Please DO NOT use this version in production, it is an early test version."[2]

PHP 8.5 is a stable production release, but use it only where your platform, plugins and dependencies support it. It has active support until 31 December 2027 and security support until 31 December 2029, while PHP 8.2 leaves security support on 31 December 2026[4]. The guide to the PHP 8.2 end of life covers that migration.

What are the new features in PHP 8.6?

The UPGRADING file at the php-8.6.0RC3 tag is the most reliable list, because it describes what was actually merged[5]. These are the changes most WordPress, WooCommerce and Magento developers will notice.

Partial function application. A call with ? or ... in place of arguments no longer runs the function; it returns a closure that waits for the missing arguments, keeping the original's types[6]. It finishes what PHP 8.5's pipe operator started: a pipe step that needs more than one argument no longer has to be wrapped in a closure.

PHP
$slug = '  Hello World From PHP  '
    |> trim(...)
    |> strtolower(...)
    |> str_replace(' ', '-', ?);

var_dump($slug); // string(20) "hello-world-from-php"

On PHP 8.5.11 the same code stops with a parse error at the ?. Every parameter created by a ? placeholder is required, even where the original parameter was optional[7].

clamp(). clamp($value, $min, $max) returns the value when it is in range and otherwise the nearest bound, and throws a ValueError when the minimum is larger than the maximum[5][8]:

PHP
var_dump(clamp(15, 0, 10)); // int(10)
var_dump(clamp(-3, 0, 10)); // int(0)
clamp(5, 10, 0);            // throws ValueError: $min is larger than $max

Readonly properties with default values. public readonly int $timeout = 30; is now valid; on PHP 8.5 it is a fatal error[5].

Smaller additions. #[\Override] on class constants and enum cases, a Time\Duration class, a SortDirection enum, error positions in json_last_error_msg(), and isReadable() and isWritable() on reflected properties[5].

Changed defaults that are easy to miss:

  • Session defaults are stricter. session.use_strict_mode and session.cookie_httponly now default to 1, and session.cookie_samesite to "Lax"[5][9]. Check any code that starts a PHP session and relies on the old defaults, such as a payment return that posts back from another domain. Magento sets the HttpOnly and SameSite options from its own configuration; WordPress core and WooCommerce do not call session_start().
  • trim() now strips form feeds, as do rtrim() and ltrim()[5]. In the test, a string wrapped in form feeds trimmed to 5 characters on 8.6.0RC3 and 7 on PHP 8.5.11.

What does PHP 8.6 deprecate?

Each deprecation was voted on separately. Four failed, among them list(), and every one that passed is in UPGRADING at RC3[5][10]. They fall into two groups.

Runtime deprecations fire only when the line runs:

  • is_integer(), is_long(), is_double() and doubleval() (use is_int(), is_float() and floatval())
  • spl_object_hash() (use spl_object_id())
  • metaphone(), strcoll(), spl_classes(), mysqli_get_charset(), a third argument to define(), and objects passed to array_walk() or http_build_query()

Compile-time deprecations fire as soon as the file is loaded, whether or not the code runs:

  • returning a value from __construct() or __destruct()
  • return inside a finally block
  • let or is as the name of a class, function or constant
  • a function named readonly, or a class constant named namespace
  • ?array as the return type of __debugInfo()

A deprecation is a notice, and a correctly configured production server logs it rather than showing it. Two things make 8.6 less forgiving. First, clamp() is now built in, so a plugin or module that declares its own global clamp() without a function_exists() check stops with "Cannot redeclare function clamp()". WordPress 7.1 ships a correctly guarded clamp() polyfill, as WordPress 6.9 did for array_first() and array_last()[11]. Second, some platforms turn deprecations into exceptions, as the field note below shows.

The is deprecation has already caught a widely used library: guzzlehttp/promises has a public class called Is[12]. A request to move the deprecation to PHP 8.7 was closed on 2 October 2026, with the reply that a revert would need an RFC[13]. The Guzzle maintainer announced on 18 October 2026 that versions 2.6.0 and 3.1.0 add a replacement class, State, and that Is will be removed in 4.0.0[12]. Those releases keep Is as a deprecated class, so in a test on 8.6.0RC3 loading it still raised the notice. Guzzle ships inside WordPress plugins and is a Magento dependency, so this one deprecation reaches a long way.

What happens when WordPress, WooCommerce and Magento code runs on PHP 8.6.0RC3?

Field note: a test on release candidate 3. I used the official Docker images php:8.6.0RC3-cli and php:8.5-cli (PHP 8.5.11) with default settings. Every PHP file of four codebases was compiled with php -l under both versions, keeping only the messages that appeared on 8.6; that finds compile-time deprecations without running anything. The same code was searched for calls to the runtime-deprecated functions.

Codebase PHP files New compile-time deprecations on 8.6.0RC3 Calls to runtime-deprecated functions
WordPress 7.1.3 core 1,315 1, in a file WordPress never loads on PHP 8.1 or later 1, in the bundled getID3 library
12 widely used WordPress plugins 7,567 8, in 6 of the 12 plugins 4, in 2 plugins
WooCommerce 11.2.1 3,664 1, a constructor that returns a value 3
Magento Open Source 2.4.9, application, libraries and vendor packages, with paths matching /Test/, /tests/ and /dev/ excluded 33,378 21, 7 of them in Magento's own code 28 lines in Magento's own code

The lint comparison found one new compile-time deprecation in WordPress core, in wp-includes/php-compat/readonly.php, which WordPress loads only below PHP 8.1. This does not establish runtime compatibility with PHP 8.6. Six of the twelve plugins raised something, including a return inside a finally block and an SEO plugin's bundled copy of Guzzle's Is class.

Magento was the real finding. Its bootstrap sets error_reporting(E_ALL) and registers an error handler that throws an exception for every reported error, deprecations included. With that handler in place, I loaded five classes the lint had flagged, among them Magento's ModuleList, plus one control class. On PHP 8.5.11 all six loaded. On 8.6.0RC3 the five flagged classes threw "Deprecated Functionality" exceptions and the control loaded normally. bin/magento --version printed "Magento CLI 2.4.9" on PHP 8.5.11; on 8.6.0RC3 it exited with status 1, stopped by a spl_object_hash() deprecation in laminas-servicemanager, one of Magento's dependencies.

That is not a fault in Magento: Adobe supports 2.4.9 on PHP 8.5 only and has said nothing yet about 8.6[14]. It shows how far the deprecations reach, and why no Magento store should run an 8.6 build before Adobe supports it.

Field note. The same pattern showed up with PHP 8.5. On a WordPress site, a plugin that was not ready for 8.5 kept the site on PHP 8.4 until its vendor shipped an update. The platform was ready first; a single plugin set the pace. Expect the same with 8.6.

Why one deprecation stopped bin/magento on PHP 8.6.0RC3. Step 1: a Magento dependency, laminas-servicemanager, calls spl_object_hash(). Step 2: PHP 8.6.0RC3 raises a deprecation notice for that call; PHP 8.5.11 raises nothing. Then two paths. On the left, most PHP code under production settings: the notice is logged and the code keeps running. On the right, Magento's error handler: the bootstrap reports every error and the handler throws an exception for each one, deprecations included, so the command exits with status 1 before printing its version. A band at the foot says that on PHP 8.5.11 the same command printed Magento CLI 2.4.9, and that Adobe supports Magento 2.4.9 on PHP 8.5 only.
On PHP 8.6.0RC3, Magento’s own error handler turned a dependency’s deprecation notice into an exception.

Which PHP 8.5 features can WordPress and Magento code use now?

PHP 8.5 brought the pipe operator, clone() with new property values, the #[\NoDiscard] attribute, a built-in URI extension, and array_first() and array_last()[15]. Whether your code may use them depends on the oldest PHP version it must run on, not on your own server:

  • WordPress supports PHP 8.5 from WordPress 6.9[16], recommends 8.3 or later and still runs on 7.4[17]. A plugin published on WordPress.org must work on every PHP version it declares.
  • WooCommerce states PHP 8.3 or later, "tested up to PHP 8.4"[18]; 8.5 is not on its requirements page yet. WooCommerce 11.6, planned for February 2027, will require PHP 8.1[19].
  • Magento 2.4.9 supports PHP 8.5 only; 8.4 is allowed for upgrades and not recommended for production[14][20]. A module written only for 2.4.9 can use 8.5 syntax; one that must also install on 2.4.8 cannot.

So 8.5 syntax is safe in custom code that runs only on your own PHP 8.5 servers: a site-specific plugin or theme, or a Magento 2.4.9 module. In anything distributed to others, keep syntax compatible with the lowest PHP version you declare. WordPress polyfills provide selected functions, including array_first(), array_last() and clamp(); they cannot provide newer language syntax[11][15].

The first snippet in this article runs on PHP 8.5 today if its last step is written as an arrow function, (fn (string $s): string => str_replace(' ', '-', $s)), instead of the ? placeholder. clone() with new values makes immutable value objects much shorter, because readonly properties can be changed while copying:

PHP
final readonly class Money
{
    public function __construct(public int $amount, public string $currency) {}

    public function withAmount(int $amount): static
    {
        return clone($this, ['amount' => $amount]);
    }
}

$sale = new Money(1999, 'GBP')->withAmount(1499);
var_dump($sale->amount, $sale->currency); // int(1499) string(3) "GBP"

Both gave the same output on PHP 8.5.11 and 8.6.0RC3. #[\NoDiscard] suits functions whose result must not be ignored, such as one that reports whether stock was reserved; ignoring it raises a warning unless the call is cast to (void)[15]. The URI extension follows two standards that disagree: given the same address, the RFC 3986 parser in the test kept an explicit :443 port and the browser-style WHATWG parser dropped it. Pick one standard per job.

How do you check a PHP 8.6 fix?

Treat every fix as a claim until a test on both PHP versions agrees. Three cautions come out of the test:

  • Check 8.6 claims against the release itself. Older answers, tutorials and tools predate PHP 8.6. They may read str_replace(' ', '-', ?) as a syntax error, or suggest adding a global clamp() helper, which is exactly the declaration that fails on 8.6. Use the UPGRADING file for the exact release candidate, and treat any 8.6 claim you cannot point to there as unverified.
  • The tempting fix is to hide the notice. Lowering error_reporting or adding @ hides a deprecation without fixing it, and in Magento it bypasses a handler that exists on purpose. For a third-party library such as Guzzle, use a release that carries the maintainer's fix and follow its migration notes; never edit files under vendor/.
  • Let the evidence decide. The lint comparison above is the method: compile on both versions, keep only the new messages, make one fix per file, and let the test suite on both versions decide. The PHP 8.2 end-of-life guide describes the same pattern with Rector and PHPStan.

What should you do before 19 November 2026?

  1. Keep production on a PHP version supported by your complete stack. None of WordPress, WooCommerce or Adobe lists PHP 8.6 as supported yet. Ask your host which PHP versions it offers and when it plans to add 8.6, because a host that is behind also limits what your code may use.
  2. Test on a staging copy or in CI, never on a live site: compile every file with php -l on an 8.6 release candidate and compare with your current version.
  3. Search your own code for the runtime-deprecated functions above, and for any global clamp() without a function_exists() check.
  4. List the dependencies that need an update or a migration, starting with guzzlehttp/promises, where 2.6.0 and 3.1.0 add the replacement State, so find the callers that still load Is, bundled copies included, and any package with a class named Is or Let.
  5. Check session behaviour wherever your code starts a PHP session, especially cross-domain payment returns.
  6. Recheck at general availability. The final build and the platforms' own support statements decide what is safe in production.

For Magento, the Magento 2.4.9 upgrade guide on extension compatibility and PHP 8.5 comes first; PHP 8.6 is a question for after Adobe adds it to the system requirements.

References

Numbers in square brackets in the text link to these sources.

  1. PHP 8.6 release timetable (PHP wiki, todo/php86) (opens in a new tab).Used for: the release dates for RC3 to RC5 and general availability.
  2. PHP 8.6.0 RC3 available for testing (php.net news, 8 October 2026) (opens in a new tab).Used for: RC3’s date and the testing-only warning.
  3. No PHP 8.6 RC 1 (Daniel Scherzer, release manager) (opens in a new tab).Used for: why there was no RC1.
  4. Supported Versions (php.net) (opens in a new tab).Used for: support end dates for PHP 8.5 and 8.2.
  5. UPGRADING at tag php-8.6.0RC3 (php-src on GitHub) (opens in a new tab).Used for: the list of changes and deprecations at RC3.
  6. RFC: Partial Function Application v2 (PHP wiki) (opens in a new tab).Used for: how partial function application works.
  7. RFC: Partial Function Application, Handling of Optional Parameters (PHP wiki) (opens in a new tab).Used for: that placeholder parameters are always required.
  8. RFC: clamp v2 (PHP wiki) (opens in a new tab).Used for: the clamp() behaviour and its error.
  9. RFC: Session security defaults (PHP wiki) (opens in a new tab).Used for: the stricter session defaults.
  10. RFC: Deprecations for PHP 8.6 (PHP wiki) (opens in a new tab).Used for: which deprecations were accepted and which failed.
  11. wp-includes/compat.php at WordPress 7.1.3 (wordpress-develop on GitHub) (opens in a new tab).Used for: the clamp() polyfill and PHP 8.5 helper functions in WordPress.
  12. Using "is" as a class name is deprecated since 8.6 (guzzle/promises issue 244) (opens in a new tab).Used for: the Guzzle Is class problem, its replacement State and the 18 October announcement.
  13. Consider deferring the "is"/"let" identifier deprecation to PHP 8.7 (php-src issue 23990) (opens in a new tab).Used for: the closed request to defer the deprecation.
  14. Adobe Commerce system requirements (Adobe Experience League) (opens in a new tab).Used for: Magento 2.4.9 PHP support.
  15. PHP 8.5 release announcement (php.net) (opens in a new tab).Used for: the PHP 8.5 features.
  16. PHP Compatibility and WordPress Versions (WordPress Core Handbook) (opens in a new tab).Used for: WordPress support for PHP 8.5.
  17. Requirements (WordPress.org) (opens in a new tab).Used for: WordPress PHP recommendations and minimum.
  18. Server requirements (WooCommerce documentation) (opens in a new tab).Used for: WooCommerce PHP requirements and tested version.
  19. New Requirement for WooCommerce 11.6: PHP 8.1+ (WooCommerce Developer Blog, 29 September 2026) (opens in a new tab).Used for: the WooCommerce 11.6 PHP 8.1 requirement.
  20. Adobe Commerce 2.4.9 release notes (Adobe Experience League) (opens in a new tab).Used for: the PHP versions for Magento 2.4.9.

Image credit: the PHP logo is by Colin Viebrock, used unaltered under CC BY-SA 4.0 (opens in a new tab).

Leave a Reply

Your email address will not be published. Required fields are marked * See the privacy policy for how comments are handled.