Web Design

What Is Shipping in PHP 8.6: The Feature Set Is Locked, and the Deprecations Are the Work

PHP 8.6 reached Beta 2 on August 27, 2026 with general availability scheduled for November 19, 2026, and because the soft feature freeze passed at Beta 1 on August 13 with all RFC voting concluded, the feature set is now settled, headlined by Partial Function Application which was merged during alpha 3 after a unanimous 33 to 0 vote, alongside a clamp function, readonly property defaults, a new polling API and a Duration class, with deprecations covering returning from a finally block and the SplFileObject CSV methods.

PHP 8.6 reached Beta 2 on August 27, 2026. General availability is scheduled for November 19. Between those two dates almost nothing about the feature list will change, and that is what makes this the moment the release becomes worth reading about rather than speculating about.

The reason is the freeze schedule. The soft feature freeze landed with Beta 1 on August 13, and the condition attached to it was that all RFCs must have their voting concluded. Everything that was going to make 8.6 had already been decided a fortnight ago. This piece covers the schedule that locks the release, the language feature that headlines it, the smaller additions that will show up in real code sooner, the deprecations that will actually cost you time, a session default change that can alter behavior quietly, and what to do between now and November. If you maintain a Symfony application, our guide to Symfony 7 against Symfony 6 covers the framework side of this cycle.

The schedule that makes php 8.6 worth reading now

Straight from the release plan on the PHP wiki, which is the authoritative version.

Date Milestone
August 13, 2026 Beta 1, and the soft feature freeze. All RFCs must have voting concluded.
August 27, 2026 Beta 2
September 10, 2026 Beta 3
September 22, 2026 Hard feature freeze. Features merge only with release manager approval.
September 24, 2026 RC1, then RC2 on October 8, RC3 on October 22, RC4 on November 5
November 19, 2026 General availability

Four release candidates across seven weeks is a long stabilization tail, and it is the part of the calendar that matters for planning. Drupal’s own release engineering runs on the same PHP cadence, which we traced in how Drupal is built on Symfony. The features are settled; what happens between now and November is bug fixing. If you are deciding when to start testing, the answer is that the target has stopped moving.

Partial function application is the headline, and it actually landed

The significant language change in this release is Partial Function Application, and it is worth being precise about its status because major PHP features have a history of being discussed for years without shipping.

This one shipped. The RFC is marked Implemented, merged during alpha 3, targeting 8.6, and it passed unanimously at 33 votes to 0. A vote with no dissent and no abstentions is unusual in PHP internals and says something about how uncontroversial the design ended up being.

What it does is let you create a closure by calling a function with placeholders instead of arguments. A ? marks a single argument position and ... means the remaining arguments. The RFC’s own example is the clearest statement of the benefit:

Before With partial application
array_map(static fn(string $s) => str_replace('hello', 'hi', $s), $arr) array_map(str_replace('hello', 'hi', ?), $arr)

The practical payoff is in callback-heavy code. Anywhere you currently write a one-line arrow function purely to reshape an existing function’s signature, this replaces it. It also pairs with the pipe operator, which is worth flagging because the two get discussed together and they arrived separately: the pipe operator is a PHP 8.5 feature, not an 8.6 one.

The smaller additions you will use sooner

The headline feature changes how you write functional code. These change smaller things more often.

clamp() finally exists as a built-in, constraining a value between a minimum and a maximum rather than requiring the nested min(max()) idiom everyone has been writing by hand.

Reflection gains ReflectionProperty::isReadable() and isWriteable(), which matter more than they sound now that property access rules have grown hooks, readonly and asymmetric visibility. ReflectionParameter::getDocComment() also arrives, which is useful for anything doing attribute-adjacent introspection.

There is a new \Time\Duration class for time arithmetic, a built-in SortDirection enum with Ascending and Descending cases, and enums gain the ability to implement __debugInfo(). A new Io\Poll namespace provides I/O multiplexing backed by epoll and WSAPoll.

json_decode() and json_last_error_msg() now report the line and column where parsing failed, which is a small change that will save real debugging time on malformed payloads. Brent Roose’s running list of what is new in 8.6 is the most complete public inventory of the smaller items if you want the full set rather than the highlights.

The deprecations are where the work is

This is the section to read if you maintain anything large, because deprecations are what turn a version bump into a sprint.

Returning from a finally block is deprecated. The reasoning is that it silently discards exceptions and return values from the try block, which produces bugs that are genuinely hard to see. If your codebase has a return inside a finally, it is doing something subtle, and 8.6 will start telling you so.

The SplFileObject CSV methods are deprecated: fgetcsv(), fputcsv(), setCsvControl() and getCsvControl(). Anything reading or writing CSV through SplFileObject rather than the procedural functions is affected.

A group of long-standing aliases go too, including is_double(), is_integer(), is_long() and doubleval(). These have had canonical spellings for years, so the fix is mechanical, but it is mechanical across every file that uses them.

None of these break anything in 8.6. They emit deprecation notices, and the breakage arrives in 9.0. The reason to care now is that a deprecation notice in a hot code path can flood logs, and in applications that treat notices as errors it can do worse than that. Our piece on what shipped in WordPress 7.1 covers the same dynamic on the CMS side, where deprecation cycles land on plugin authors rather than core.

A session default change that alters behavior quietly

One item in this release is not a feature or a deprecation and deserves separate attention.

session.use_strict_mode and session.cookie_httponly now default to 1. Both changes are security improvements and both are correct. Strict mode makes PHP reject session IDs it did not generate, which closes session fixation. The httponly flag keeps the session cookie out of reach of JavaScript.

The reason to flag it is that these are behavior changes shipped as defaults, and defaults are the most under-tested part of any upgrade. An application that was silently relying on accepting an externally supplied session ID will stop working, and it will stop working in a way that looks like an unrelated login bug. Anything that reads the session cookie from client-side JavaScript will simply stop seeing it. Neither will show up in a static analysis pass. The pattern of a security default quietly changing application behavior is one we covered from the WordPress side in the Connectors API encryption at rest work.

Worth noting too that Beta 2 itself carries a SessionHandler::validateId() implementation, which is what makes strict mode function correctly for custom session handlers. That is a fix arriving alongside the default, not before it.

What Beta 2 specifically brought

Beta 2 was tagged two days ahead of its scheduled slot by release manager Matteo Beccati, according to coverage of the release. Two things in it stand out.

The SNMP extension got a real overhaul, gaining AES-192 and AES-256 security protocols, dynamic MIB tree loading through snmp_read_mib(), and several new output format controls. SNMP is not a glamorous extension and it rarely gets attention, so a release that modernizes its crypto is worth noting for anyone doing network monitoring in PHP.

The larger item is a memory-safety sweep. The same coverage lists use-after-free fixes in the DOM extension tied to DOMDocument::xinclude() and cloned namespace nodes, an Opcache JIT crash in inheritance cache compilation, corrections to nested yield from in generators, a double-free in IntlGregorianCalendar, a PDO_PGSQL lazy-fetch correction, and ZipArchive stream handling fixes. That is a broad list, and it is the kind of work that makes a beta worth installing on a test box rather than waiting for RC.

What to do between now and November

Four things, in order of how much time they save.

Run your test suite on Beta 2 and read the deprecation notices, not the failures. The failures will be few. The notices are the actual inventory of work, and getting that list in August rather than November is the entire point of a beta.

Grep for the mechanical ones now. return inside finally, SplFileObject CSV calls, and the is_double family are all findable with a search and fixable without design decisions. Do them while they are cheap.

Test session behavior explicitly. The two defaults that flipped will not surface in unit tests. Log in, log out, and check anything that touches the session cookie from JavaScript.

Do not adopt partial function application in library code yet. It is a lovely feature and it is also 8.6-only, which means using it sets your minimum version. In application code that you control, that is a decision you can make in November. In a package other people depend on, it is a decision you make for them.

Frequently Asked Questions

When does php 8.6 actually release?

General availability is November 19, 2026. Beta 2 arrived August 27, with Beta 3 on September 10, a hard feature freeze on September 22, and four release candidates running from September 24 through November 5.

Is the feature list final?

Effectively yes. The soft feature freeze at Beta 1 on August 13 required all RFCs to have concluded voting. After the hard freeze on September 22, features merge only with release manager approval.

What is partial function application?

A way to create a closure by calling a function with placeholders instead of arguments, using `?` for a single argument position and `…` for the rest. It replaces the arrow functions people write purely to reshape a signature for a callback.

Is the pipe operator part of this release?

No. The pipe operator is a PHP 8.5 feature. It gets discussed alongside partial function application because the two work well together, but they shipped in different versions.

Which deprecations should I act on first?

Returning from a `finally` block, because it usually indicates a real bug rather than a style choice. Then the SplFileObject CSV methods and the `is_double`, `is_integer`, `is_long` and `doubleval` aliases, which are mechanical find-and-replace work.

Will the deprecations break my application in 8.6?

No. They emit deprecation notices in 8.6 and the removal comes in 9.0. The practical risk in the meantime is log volume in hot paths, and applications configured to treat notices as errors.

What changed about sessions?

`session.use_strict_mode` and `session.cookie_httponly` now default to `1`. Strict mode makes PHP reject session IDs it did not generate; httponly hides the session cookie from JavaScript. Both are improvements and both are behavior changes worth testing deliberately.

Is Beta 2 worth installing?

On a test machine, yes. It carries a wide memory-safety sweep across the DOM, Opcache JIT, generators, Intl, PDO_PGSQL and ZipArchive, so it is a materially different build to test against than Beta 1.

Digital Matters

Web Design Desk