Software 45203 Published by

PHP's team shipped php-8.6.0RC7 today as the last release candidate before the first stable 8.6 lands on November 19, 2026. The build is tiny by design, just an array_map() first-class callable fix and an OpenSSL TLS use-after-free patch, but it already includes the critical PHP2Shell remote-code-execution fixes from October. The headline feature most developers associate with 8.6 is partial function application, letting you pre-fill arguments with ? or ... placeholders to skip closure boilerplate.



PHP 8.6.0 RC7 Is the Last Stop Before Stable

Tagged November 12, PHP's final release candidate carries just two fixes and one week's worth of waiting before the first stable 8.6 lands.

PHP's team shipped php-8.6.0RC7 today, and it's deliberately unexciting, which is exactly the point. Two commits. Tagged at commit b63cd83 and signed by release manager Joe Ferguson. The authoritative NEWS file lists them, and they're both hardening, not feature work.

Screenshot_from_2026_06_30_15_03_26

First, a core fix from Chris Abner. An array_map() optimization wasn't resolving the function name of a first-class callable correctly. Second, an OpenSSL fix from Ilia Alshanetsky. It closed a use-after-free in TLS server ALPN and Windows certificate checks that fired when a session stream got closed mid-handshake.

That's it. Two changes. But it lands right behind predecessors: RC6 dropped November 10, and RC5 came on November 5. Five RCs, roughly every week or so, in the final stretch. It usually means testers found a few more edge cases to close. Keep in mind that the feature set has been frozen since September 22, so whatever you test now is what ships on GA day: November 19, 2026.

The release notes are thin on purpose. The GitHub page for the tag reads as a single line, "Tag for php-8.6.0RC7", with the real detail living in the NEWS and UPGRADING files in the php/php-src repo. Head here for the raw source if you want to read the diffs yourself.

The Phantom RC1

There's a small wart in the timeline worth knowing about if you're counting. The September 24 entry was labeled RC2 by mistake. A packaging error meant there was never an official RC1, so the cycle effectively ran Beta 3 into the hard feature freeze, straight to RC2. Daniel Scherzer wrote it up. So RC7 is technically the "seventh" candidate even though only six were ever actually tagged. Nobody's perfect, and the project was candid about it.

What RC7 does embed, though, is the real headline of the autumn: the PHP2Shell emergency fixes. Those shipped in RC4, which means every candidate since — RC5, RC6, RC7 included — already carries them. If you run RC7 for a week, you're already running hardened code against two CVSS 9.2 criticals.

Those flaws are CVE-2026-109618 (RCE via out-of-memory corruption) and CVE-2026-109619 (RCE via stale global state). Both let an attacker execute code unauthenticated, essentially across every web-serving PHP deployment — PHP-FPM, Apache mod_php, php-cgi, FrankenPHP, LiteSpeed. Researchers from Calif, OpenAI, and Wiz found them. CISA added both to its Known Exploited Vulnerabilities list on October 26, and the UK's NCSC was blunt enough to suggest taking unpatchable systems offline. Fixed versions landed in 8.5.12, 8.4.27, 8.3.36, and 8.2.35, with source backports further down to 7.4.

The Feature That Matters

If you ask PHP developers what 8.6 is famous for, nearly everyone names partial function application. It's the most-debated change in the cycle, surfacing from an RFC first pitched in 2021 after years of internals arguing.

The syntax itself is quick to absorb. Drop a question mark where an argument would go, and PHP hands you back a closure that remembers the open slot instead of running the call right away.

// The old way
$slug = fn($text) => str_replace(' ', '-', $text);

// PHP 8.6+
$slug = str_replace(' ', '-', ?);

$slug('Hello World'); // "Hello-World"

It sounds like a party trick until you count how many closures in the wild just wrap another function anyway. Inside array_map(), array_filter(), Laravel collection chains — it's boilerplate you can now delete.

$startsWithAdmin = str_starts_with(?, 'admin.');
array_filter(['admin.users', 'web.home', 'admin.posts'], $startsWithAdmin);
// ['admin.users', 'admin.posts']

A ... placeholder does the same thing but grabs everything remaining. Named arguments work too, as do magic methods and static factories. You still can't partially apply a constructor with new. The implementation, finalized as partial_function_application_v2, preserves the original signature so reflection and IDEs aren't left guessing.

Other Things In The Box

Partial application is the poster child, but 8.6 carries a lot more. A few standouts from the UPGRADING notes:

  • clamp($value, $min, $max) — clamps a value, throws ValueError if you swap the bounds.
  • Time\Duration — immutable, nanosecond-precision durations.
  • Io\Poll — a polling API abstracting epoll, kqueue, Solaris ports, and WSAPoll, aimed mostly at internals but useful for async runtimes too.
  • A stream errors API — stream_last_errors(), StreamError, and a 50+ value StreamErrorCode enum.
  • Post-quantum crypto in Sodium — X-Wing KEM, standalone ML-KEM768, and IP-encryption primitives (needs libsodium ≥ 1.0.22).
  • OpenSSL TLS 1.3 early data, session resumption, and external PSK support for streams.

Readonly property defaults, #[\Override] on constants, and direct writes to objects held in constants round out the language layer.

Where It Can Bite

The deprecations are mostly noise, but the Mbregex one is worth flagging. The Oniguruma backend bundled with mbstring is now deprecated because it's "no longer maintained," nudging people toward PCRE2. That's a real shift for multibyte-regex users who haven't looked at their stack in a while.

The secure-by-default session settings are the change most likely to break something quietly. session.use_strict_mode is now 1, session.cookie_httponly is now 1, and session.cookie_samesite is now "Lax." If your app reads the session cookie from JavaScript or leans on cross-site cookie delivery, you'll need to set these explicitly or behavior changes on you.

A few other landmines: more functions now throw ValueError on bad input, preg_grep() returns false instead of a partial array on PCRE errors, and trim() now also strips the form-feed character. Minor, but they'll show up in logs.

What To Do

This is the moment to test, not panic. The feature freeze is over, so the RC list is final. But most big frameworks still tested their CI against 8.3 through 8.5 at time of writing, not 8.6.

Prudent plan: spin up an allowed-to-fail CI job on the 8.6 RC with error_reporting=E_ALL, fix deprecations as they surface, and only move production after your key dependencies declare 8.6 support. If you're still on 8.2, note it hits End Of Life December 31, 2026, a jump to 8.6 now saves you from another migration in the spring.

The RC7 build is exactly the kind of conservative final candidate that bodes well for a clean GA. Two fixes, PHP2Shell already baked in, nothing experimental on the table.

Release php-8.6.0RC7 · php/php-src

Tag for php-8.6.0RC7

Release php-8.6.0RC7 · php/php-src