PHP 8.6.0RC3 có thể khởi động một ứng dụng Laravel 13 nhỏ, nhưng chưa thể xem là đường nâng cấp sạch. Trong matrix kiểm tra ngày 12/10/2026, Laravel 13.35.0 boot được và 2/2 test mẫu đều xanh trên RC3; ngay trước đó, Composer lại chặn vì hai dependency chỉ khai báo hỗ trợ đến PHP 8.5.
Đây chính là lý do nên thử release candidate bằng một lane CI riêng thay vì nhìn mỗi constraint php: ^8.3 rồi đổi runtime production. PHP công bố RC3 ngày 08/10/2026, yêu cầu cộng đồng kiểm thử và ghi rõ không dùng bản này cho production. RC4 đang được dự kiến vào ngày 22/10; bài viết này chỉ phản ánh RC3 tại thời điểm kiểm tra.
Mục lục [Hiển thị]
RC3 đang ở đâu, và Laravel hỗ trợ tới đâu?
Trang pre-release chính thức cung cấp PHP 8.6.0RC3 cho Windows cùng checksum SHA-256. Bản NTS x64 dùng trong fixture có hash ed902df5ac33a696ce5e43f025550362d0644c077efd91a3eb3a366900fe9bfa, khớp giá trị PHP.net công bố. Runtime đối chứng là PHP 8.5.11 NTS x64.
Cần tách hai chuyện: Composer có thể hiểu một constraint rộng là hợp lệ, nhưng framework chưa chắc đã công bố support. Bảng support trong Laravel 13 release notes hiện ghi PHP 8.3–8.5 cho Laravel 13, chưa có PHP 8.6. Vì vậy kết quả bên dưới là một compatibility probe trên bản chưa được Laravel liệt kê chính thức, không phải chứng nhận “Laravel đã hỗ trợ PHP 8.6”.
Môi trường kiểm tra có gì?
| Thành phần | Giá trị |
|---|---|
| Hệ điều hành | Windows 11 Pro build 26300, x64 |
| Runtime đối chứng | PHP 8.5.11 NTS, VS17 |
| Runtime thử nghiệm | PHP 8.6.0RC3 NTS, VS18 |
| Ứng dụng | Laravel 13.35.0 từ skeleton 13.0 |
| Dependency | Cùng một composer.lock, 107 package |
| Composer / PHPUnit | Composer 2.10.2 / PHPUnit 12.5.38 |
| Extension nạp rõ ràng | mbstring, OpenSSL, fileinfo, PDO SQLite, SQLite, cURL |
Hai runtime chạy với -n để không nạp php.ini của máy. Các extension cần cho Laravel được truyền rõ trên command line; cùng script, cùng dữ liệu và cùng lock file. Cách này làm khác biệt do runtime dễ nhìn hơn, nhưng cũng có giới hạn: nó không đại diện cấu hình FPM, OPcache, web server, Redis, queue worker hoặc extension production.
php -n -d extension_dir=ext \
-d extension=php_mbstring.dll \
-d extension=php_openssl.dll \
-d extension=php_pdo_sqlite.dll \
artisan about --only=environment
php -n -d extension_dir=ext \
-d extension=php_mbstring.dll \
vendor/phpunit/phpunit/phpunit --colors=never
Nếu cần dựng một app nhỏ để lặp lại quy trình, bài Laravel Installer 5.31 có phần phân biệt skeleton ứng dụng với package fixture. Còn với dự án đang ở Laravel 12, nên xử lý đường nâng framework trước theo checklist nâng Laravel 12 lên 13, rồi mới thêm PHP 8.6 vào matrix.
Bốn thay đổi runtime tái lập được
UPGRADING của nhánh PHP-8.6 dài hơn một nghìn dòng. Fixture chỉ chọn những case nhỏ, có đầu vào và kết quả đối chứng rõ ràng, thay vì biến bài thành bản dịch changelog.

| Case | PHP 8.5.11 | PHP 8.6.0RC3 | Ý nghĩa cần kiểm |
|---|---|---|---|
session_encode() với session rỗng | false | Chuỗi rỗng | Code dùng false để suy ra “không có dữ liệu” có thể rẽ nhánh khác. |
trim("\fvalue\f") | Giữ form feed | Loại form feed | Normalizer và chữ ký dựa trên chuỗi đã trim cần test lại. |
preg_grep('/./u', ...) gặp byte UTF-8 lỗi | Trả mảng kết quả một phần | false | Đừng giả định luôn nhận mảng; cần xử lý lỗi tách biệt. |
array_filter(..., 999) | Vẫn trả mảng | Ném ValueError | Wrapper truyền mode động có thể chuyển từ “chạy được” sang exception. |
Mỗi nhóm có một negative control hợp lệ: trim(" value "), preg_grep() trên hai chuỗi UTF-8 đúng và array_filter() với ARRAY_FILTER_USE_BOTH đều cho cùng kết quả ở hai runtime. Đây là chi tiết nhỏ nhưng quan trọng; nếu control cũng đổi thì fixture chưa cô lập đúng thứ cần đo.
Bài partial function application trên PHP 8.6 tập trung vào cú pháp mới. Matrix lần này đi hướng ngược lại: tìm hành vi cũ có thể lệch dù ứng dụng không dùng feature mới nào.
Session mặc định an toàn hơn không tự động làm Laravel vỡ
PHP 8.6 đổi ba mặc định của ext/session: session.use_strict_mode=1, session.cookie_httponly=1 và session.cookie_samesite=Lax. Khi đưa một session ID chưa tồn tại vào native file handler, PHP 8.5.11 chấp nhận đúng ID dài 24 ký tự; RC3 từ chối và sinh ID mới dài 32 ký tự. Positive control này chứng minh strict mode thực sự tham gia, không chỉ là một con số từ ini_get().
Tuy nhiên, không nên suy ra mọi app Laravel sẽ đổi cookie ngay. Laravel quản lý session qua driver và config/session.php; skeleton hiện dùng database driver, đồng thời đã đặt http_only=true và same_site=lax. Probe boot cho thấy hai giá trị Laravel này giống nhau trên PHP 8.5 và 8.6, dù mặc định PHP phía dưới đã đổi.
Vùng rủi ro thực tế là code gọi trực tiếp session_start(), bridge với ứng dụng legacy, package tự cài native save handler hoặc handler tùy biến phụ thuộc vào ID do client gửi lên. Với nhóm đó, cần test validateId(), create_sid(), empty session và updateTimestamp(). Đừng vội hạ session.use_strict_mode về 0 chỉ để test xanh; làm vậy là bỏ lớp bảo vệ chống session fixation thay vì sửa assumption cũ.
Composer mới là blocker đầu tiên
Root project khai báo php: ^8.3, nên nhìn riêng dòng này thì 8.6 có vẻ ổn. Nhưng composer check-platform-reqs trên RC3 thất bại: nette/schema 1.3.6 yêu cầu PHP 8.1–8.5 và nette/utils 4.1.5 yêu cầu PHP 8.2–8.5. Lệnh composer why-not php 8.6.0 chỉ đúng hai package này.
Ở cùng trạng thái dependency, artisan about vẫn boot được trên RC3 và báo Laravel 13.35.0. Chạy PHPUnit trực tiếp bằng binary RC3 cũng cho 2 test, 2 assertion đạt. Kết quả này không mâu thuẫn với Composer: autoload hiện có có thể chạy, còn metadata nói tổ hợp đó chưa được dependency cam kết hỗ trợ.

Đây là chỗ dễ bị một bộ test xanh đánh lừa. Hai test mặc định chỉ chạm một unit case và một request rất cơ bản; chúng không đi qua đăng nhập, upload, mail, queue, cache, session tùy biến hay package của dự án thật. Bỏ qua platform check bằng --ignore-platform-req=php chỉ phù hợp cho lane thăm dò có kiểm soát, không phải cách mở khóa production.
Checklist thêm PHP 8.6 RC vào CI
- Pin đúng runtime. Ghi patch version, nguồn tải và checksum. Không dùng tag mơ hồ như
latest. - Giữ lock file giống production. Chạy
composer check-platform-reqsvàcomposer why-not php 8.6.0trước test suite. - Boot framework trước. Chạy
artisan about, config cache và một request smoke test để bắt lỗi khởi tạo sớm. - Thêm reproduction sát app. Ưu tiên login/session, parser chuỗi, regex nhận input người dùng, upload, queue và package có extension native.
- Giữ control. Mỗi case “có thể vỡ” cần một đầu vào bình thường để biết test harness vẫn hoạt động.
- Cho phép lane RC thất bại có chủ đích. Nó dùng để gom blocker sớm; chưa nên khóa merge của nhánh production cho tới khi framework và dependency công bố hỗ trợ.
Nếu dự án có static analysis, hãy chạy nó bằng codebase hiện tại nhưng đừng coi parser hiểu cú pháp là bằng chứng runtime tương thích. Tương tự, Composer resolve được không thay thế integration test, và integration test xanh không thay thế metadata support. Ba cổng này trả lời ba câu hỏi khác nhau.
Nên thử RC3 hay chờ stable?
| Tình huống | Quyết định hợp lý |
|---|---|
| Dự án có CI linh hoạt, package nội bộ hoặc native extension | Thêm lane RC ngay để tìm blocker và gửi issue sớm. |
| App Laravel thông thường, dependency hiện còn chặn 8.6 | Giữ production ở 8.5; theo dõi release package rồi chạy lại matrix. |
| Có custom native session handler hoặc bridge legacy | Viết reproduction cho strict mode, ID validation và empty session trước. |
| Không có staging disposable hoặc test hồi quy đủ sâu | Chờ framework/dependency công bố support; đừng đổi production chỉ vì app boot. |
Kết luận ngắn: PHP 8.6 RC3 đã đủ tốt để bắt đầu compatibility audit, nhưng fixture này vẫn có blocker Composer rõ ràng và Laravel 13 chưa liệt kê PHP 8.6 trong bảng support. Cứ cho RC vào một lane riêng, lưu các khác biệt tái lập được, rồi chờ dependency mở constraint. Boot được là tín hiệu khởi đầu; nâng được phải qua đủ metadata, test hồi quy và môi trường gần production.