Back to Blog
PHP 8.6: What’s Coming and What I’d Watch Before Upgrade Day
PHP 8.6 is past Beta 3 and aimed at GA on 19 Nov 2026. I walked the official schedule, the features I’d learn first, and what we actually ran on Docker beta3.
Back
Engineering
Table of contents
PHP 8.6: What’s Coming and What I’d Watch Before Upgrade Day
I’ve been watching PHP 8.6 the same way I watch most minor releases: ignore the hype posts until the timetable and the Implemented RFC list say something real.
As of 20 Sep 2026, that something is real enough. Official prep says we are past Beta 3, hard feature freeze hits 22 Sep, RC1 is 24 Sep, and GA is aimed at 19 Nov 2026. Tags through php-8.6.0beta3 are already on php-src.
So the question for me is practical. What is worth learning before RC, what will annoy me on upgrade day, and what can wait until a green test suite after GA.
I used wiki.php.net/todo/php86 plus the wiki’s Implemented list as the lock. PHP.Watch’s 8.6 page is useful as a changelog digest, not as release-manager truth on its own. Hands-on notes below come from Docker php:8.6.0beta3-cli (built 19 Sep 2026), a slim CLI image, not a full Homebrew PHP.
Where 8.6 sits right now
Soft freeze came with Beta 1 on 13 Aug, which is the point where RFC voting for the release should already be done. Hard freeze on 22 Sep means new features need RM approval. After that it is the usual RC cadence into November.
I would not put production on a beta. After RC1 I would spin a throwaway binary, run the suite, and keep Laravel / Forge / Herd images in mind because those often lag the announcement by a bit.
If someone asks “upgrade tomorrow?” my answer is no. Learn now, smoke on RC, cut over after GA when your own tests are green.
What I’d learn first
Partial function application is the language story. PFA v2 is on the Implemented list, with a follow-up RFC about optional parameters. On beta3 we verified a boring case: add(1, ?) then call (2) and get 3. That is enough for me to start reading the RFC carefully. It is not enough to standardize every pipeline on PFA before the optional-parameter edges are clear in my own notes.
Then the small APIs people will actually touch in app code.
clamp() is the obvious one. Signature is clamp(int|float $num, int|float $min, int|float $max): int|float. In range it returns $num. Out of range it returns the nearer bound. Bad bounds (min greater than max, or NAN killing the range) throw ValueError. We hit those cases on beta3. One upgrade landmine: if you already have a userland clamp() in global scope, the name collision will find you.
SortDirection is a small enum win. Ascending / Descending both resolved on the slim image. I would still check which core APIs accept it on your exact build before you rewrite sort helpers for style points.
grapheme_strrev is the Unicode-aware reverse. I care about it because strrev lies to you with emoji and combining marks. We could not run it on this Docker image (no intl), so I am not pretending we did.
PHP.Watch also calls out better location detail in json_decode errors. Quiet, useful when you are staring at a bad payload at midnight.
On the systems side, the Polling API and Time\Duration matter more if you write long-running CLI or workers. Duration showed up as Time\Duration, not a bare Duration class, which is the kind of naming detail that wastes an afternoon if you guess from a blog title. This is still not “PHP becomes Go.” Better primitives, same process model.
Secure session defaults are the quiet web-app change. On the engine defaults we saw cookie_httponly=On, samesite=Lax, use_strict_mode=On, and cookie_secure=Off. Frameworks may override some of that. I still want the engine baseline in my head before I blame Laravel.
TLS session resumption for streams is in the same bucket: interesting if you build clients or custom sockets and care about reuse. I would not lead a post with it unless I had a measured case.
What will bite on upgrade day
A few boring things tend to cause the real tickets.
clamp becomes a core function name. Rename your helpers early.
trim, ltrim, rtrim, and chop now include form-feed (\f) in the default mask. That is an accepted RFC and PHP.Watch surfaces it too. Easy to miss in string-cleaning tests.
Invalid array_filter $mode values throw ValueError instead of softer failure modes. Tighten the call sites.
Skim the 8.6 deprecations RFC and php-src UPGRADING before you tell stakeholders “drop-in.” And leave calendar room after 19 Nov for Docker tags and host images to catch up.
What we actually ran
Runtime was PHP 8.6.0beta3 (cli) on Docker php:8.6.0beta3-cli. Slim image, so treat extension gaps as image limits, not as “missing from 8.6.”
clamp(5, 0, 3) returned 3. clamp(1, 2, 5) returned 2. min greater than max raised ValueError. PFA add(1, ?) then (2) returned 3. trim("\fhi\f") returned "hi". SortDirection worked. Duration worked as Time\Duration. Session defaults matched what I listed above.
We did not run grapheme_strrev (no intl here). We did not run a Laravel Composer / PHPUnit / HTTP smoke test yet.
Before I would write a confident production upgrade guide, I still want grapheme on an image with intl, a few optional-parameter PFA cases from the follow-up RFC, and a real app suite on RC1 or later.
My take
PHP 8.6 feels like a tools-and-defaults release. PFA and clamp for day-to-day code. Sessions, TLS, and polling for the platform. Beta3 already proves the small APIs are not vapor. I would learn on RC, then upgrade after GA when the suite is green.
And no, PHP 8.6 is not TypePHP. Different product, different compatibility story. I keep them in separate posts on purpose.
Sources
- PHP 8.6 timetable
- PHP RFCs (Implemented → PHP 8.6)
- clamp RFC
- PHP.Watch: PHP 8.6
- php-src tags:
php-8.6.0beta3(and earlier alphas/betas) - Cross-check before ship: php-src
UPGRADINGon the 8.6 branch
Comments
No comments yet
Loading comments...