PHP 8.6 の正式版は、2026 年 11 月 19 日に公開される予定です。11 月 5 日には最後のリリース候補(RC5)が出ており、仕様はほぼ固まっています。 この記事は、PHP で Web サイトや業務システムを作っている・保守しているエンジニアに向けて、リリース前に自分のプロジェクトで確かめておくことを、公式の UPGRADING(変更点の一覧)と RFC(仕様の提案文書)をもとにまとめたものです。内容は 2026 年 11 月 7 日時点、8.6.0RC5 の UPGRADING にもとづいています。
リリース日程とサポート期限
PHP は毎年 11 月ごろに新しいマイナーバージョンを出し、各バージョンは「バグ修正もされる期間(アクティブサポート)」2 年と、「セキュリティ修正だけの期間」1〜2 年を経て終了します。php.net の公式表では、2026 年 11 月時点で次のようになっています。
| バージョン | 初回リリース | アクティブサポート | セキュリティサポート |
|---|---|---|---|
| 8.2 | 2022-12-08 | 終了 | 2026-12-31 まで |
| 8.3 | 2023-11-23 | 終了 | 2027-12-31 まで |
| 8.4 | 2024-11-21 | 2026-12-31 まで | 2028-12-31 まで |
| 8.5 | 2025-11-20 | 2027-12-31 まで | 2029-12-31 まで |
| 8.6 | 2026-11-19(予定) | ― | ― |
8.6 のリリースそのものより急ぎなのは、8.2 のサポートが年末で切れることです。8.2 で動いている案件は、8.6 を待たずに 8.4 か 8.5 へ上げる計画を先に立てましょう。8.6 は、新規案件や、すでに 8.4・8.5 で安定している案件の次の行き先として検討するのが現実的です。
正式版の直後は、ライブラリやホスティング会社の対応が追いついていないことがあります。本番を上げるのは、使っているパッケージが 8.6 対応を明記してからが安全です。それまでに RC で「どこが壊れるか」を洗い出しておきましょう。
いちばん影響が大きい変更:セッション Cookie の既定値
8.6 で多くのサイトに関係しそうなのが、セッション機能(session_start() などの ext/session)の既定値の変更です。RFC「session_security_defaults」が、3 項目とも反対票ゼロで可決されました。
| 設定(php.ini) | 8.5 までの既定値 | 8.6 の既定値 | ねらい |
|---|---|---|---|
session.use_strict_mode |
0 | 1 | 初期化されていないセッション ID を受け付けない(セッション固定攻撃の防止) |
session.cookie_httponly |
0 | 1 | JavaScript の document.cookie からセッション Cookie を読めなくする |
session.cookie_samesite |
未設定 | Lax |
別サイトからの POST などでは Cookie を送らない(CSRF の緩和) |
どれも、セキュリティの解説で「必ず有効にしましょう」と言われてきた設定です。すでに php.ini や .htaccess、ini_set() で明示しているサイトは、何も変わりません。影響を受けるのは、既定値のまま運用していて、しかも次のような作りになっているサイトです。
- 別サイトからの POST でログイン状態を引き継ぐ:外部の決済サービスから戻ってくるときの POST や、SAML のシングルサインオンなど。
Laxでは別サイトからの POST にセッション Cookie が付かないため、戻ってきた時点で「ログインしていない」扱いになります。 - JavaScript でセッション Cookie を読んでいる:古い Ajax の実装で、セッション ID を JavaScript から取り出してリクエストに付けているもの。
- 外から渡したセッション ID をそのまま使う:サブドメイン間で ID を受け渡すような作り。strict mode では、保存先に存在しない ID は拒否され、新しい ID に差し替えられます。
元に戻す必要がある場合は、該当するサイトだけで明示的に設定します。RFC は、別サイトからの POST が必要なら SameSite=None と Secure を組み合わせるか、トークンを使う方式に移るよう案内しています。
session.cookie_samesite = "None"
session.cookie_secure = 1
自分の環境がどの値で動いているかは、次のように確かめられます。8.5 以前の環境で 0 や空が出たら、8.6 に上げると挙動が変わる候補です。
php -r 'foreach (["use_strict_mode","cookie_httponly","cookie_samesite","cookie_secure"] as $k) { echo $k, " = ", var_export(ini_get("session.$k"), true), PHP_EOL; }'
コマンドラインと Web サーバー(PHP-FPM など)では読み込む php.ini が違うことがあるので、本番と同じ経路で確かめてください。
独自のセッションハンドラーを書いている場合は、もう 1 点あります。SessionHandlerInterface を実装したクラスに create_sid() と validateId() が無いと、8.6 では非推奨の警告が出るようになりました。strict mode では validateId() が ID の検証に使われるので、あわせて実装を見直しておきましょう。
日本語のサイトで要注意:mb_ereg 系関数の非推奨
mb_ereg_replace() や mb_split() など、マルチバイト文字に対応した正規表現関数(mbregex)が、8.6 で非推奨になりました。これらが内部で使っている正規表現ライブラリ Oniguruma の保守が 2025 年 4 月に終了したためで、RFC では PHP 9.0 での削除が予定されています。
日本語のサイトでは、全角スペースの除去や、全角・半角の判定に mb_ereg_replace() を使っているコードがよくあります。対象は mb_ereg、mb_eregi、mb_ereg_replace、mb_ereg_match、mb_ereg_search 系、mb_split、mb_regex_encoding、mb_regex_set_options などです。まず、使っている場所を探しましょう。
grep -rnE "mb_(ereg|eregi|split|regex_)" --include="*.php" .
vendor/ の中で見つかった場合は、そのパッケージの新しい版で直っていないかを確かめます。自分たちのコードであれば、多くは preg_* 関数に u 修飾子(UTF-8 として扱う指定)を付ければ置き換えられます。
- $name = mb_ereg_replace('[ \s]+', ' ', $name);
+ $name = preg_replace('/[ \s]+/u', ' ', $name);
- $words = mb_split('[、,]', $keywords);
+ $words = preg_split('/[、,]/u', $keywords);
置き換えるときは、区切り文字(/)で正規表現を囲むことと、パターンに / が含まれるならエスケープすることを忘れないでください。Oniguruma 独自の書き方を使っている場合や、文字コードが UTF-8 以外の場合は、結果が同じになるかをテストで確かめる必要があります。すぐに直せない事情があるときのために、RFC の提案者は、同じ関数を外部の拡張として提供する mb_onig を用意しています。
そのほかの非推奨と、壊れやすい変更
8.6 では非推奨がまとめて入りました。非推奨は今すぐ動かなくなるわけではありませんが、E_DEPRECATED の警告がログを埋め、PHP 9.0 で削除される予定です。よく見かけるものを抜き出します。
| 非推奨になったもの | 代わりに使うもの |
|---|---|
is_integer()、is_long() |
is_int() |
is_double()、doubleval() |
is_float()、floatval() |
spl_object_hash() |
spl_object_id() |
finally ブロックの中の return |
finally の外で値を返す |
__construct()・__destruct() で値を返すこと |
値を返さない |
define() の第 3 引数 |
指定しない |
SplFileObject::fgetcsv()・fputcsv() など CSV 系メソッド |
(UPGRADING に代替の記載なし) |
let・is をクラス名や関数名に使うこと |
別の名前にする |
finally の中の return が非推奨になったのは、try で投げられた例外が黙って捨てられてしまうからです。RFC は「黙っていることが問題だ」と説明しています。
また、非推奨ではなく挙動が変わるものもあります。たとえば trim() が既定で取り除く文字に、改ページ(\f)が加わりました。preg_grep() は、不正な UTF-8 などで処理に失敗したとき、途中までの配列ではなく false を返すようになりました。filesize() や file_exists() などのファイル関数は、引数に NUL バイトが含まれると ValueError を投げます。外部からの入力をそのままファイル名に使うコードでは、例外処理を確かめておきましょう。
これらを人の目で探すのは大変なので、RC 上でテストを走らせ、警告を拾うのが近道です。開発環境では error_reporting = E_ALL にしておけば、非推奨の警告もログに出ます。
新機能:部分関数適用・readonly の既定値・Duration
壊れる話だけでなく、書き方が良くなる機能も入っています。ここでは日々のコードに効く 3 つを紹介します。
部分関数適用(Partial Function Application)
関数を呼ぶときに、引数の一部を ? にすると、関数はその場で実行されず「残りの引数を受け取るクロージャ」が返ります。8.1 の strlen(...)(第一級呼び出し可能構文)を一般化したもので、RFC は 33 対 0 で可決されました。
// これまで:アロー関数で包む
$result = array_map(fn($s) => str_replace('hello', 'hi', $s), $arr);
// 8.6:? の位置に、あとから値が入る
$result = array_map(str_replace('hello', 'hi', ?), $arr);
? は「ちょうど 1 つの引数」、... は「0 個以上の残りの引数」を表します。8.5 で入ったパイプ演算子 |> と組み合わせると、処理を左から右へ順に読める形で書けます。UPGRADING によると、array_map() に部分適用を渡した場合は内部で foreach 相当に変換され、クロージャを作るコストもかかりません。
注意点は 2 つです。部分適用に渡した引数は、クロージャを作った時点で評価されます。また、... を使うと余分な引数がそのまま元の関数に渡るため、省略可能な引数を持つ関数では思わぬ値が入ることがあります。new によるコンストラクタ呼び出しは部分適用できません。
readonly プロパティの既定値
これまで readonly プロパティには既定値を書けず、コンストラクタで代入する必要がありました。8.6 からは宣言時に既定値を書けます。ただし、既定値が「初期化の代入」として扱われるので、コンストラクタで上書きしようとするとエラーになります。
final readonly class Rule
{
public string $className = SomeParser::class;
public function __construct(string $className) {
$this->className = $className; // Error: Cannot modify readonly property
}
}
上書きしたい値なら、これまでどおりコンストラクタの引数の既定値にするのが正解です。readonly の既定値は「固定の値を持たせたい」ときに使うもの、と覚えておくと迷いません。
Time\Duration
秒・ミリ秒・ナノ秒などの「時間の長さ」を表す、変更できないクラスです。リトライの待ち時間やタイムアウトを、単位を取り違えずに扱えます。
use Time\Duration;
$baseDelay = Duration::fromMilliseconds(100);
$attempt = 5;
$delay = $baseDelay->multiplyBy(2 ** $attempt); // 3.2 秒
< などの比較演算子で大小を比べられます。一方、+ などの算術演算子は使えないので、足し算は add()、引き算は sub() で行います。
RC で試す手順と、移行の進め方
正式版を待たずに試すなら、公式 Docker イメージの RC 版が手軽です。Docker Hub には php:8.6-rc-cli-alpine などのタグが公開されています。プロジェクトのディレクトリで、テストをそのまま走らせてみましょう。
docker run --rm -v "$PWD":/app -w /app php:8.6-rc-cli-alpine \
php -d error_reporting=E_ALL vendor/bin/phpunit
拡張が足りない場合は、このイメージに拡張を足した Dockerfile を用意します。composer install が PHP のバージョン制約で止まるときは、まず依存パッケージが 8.6 を許可しているかを確かめましょう。
移行は、次の順に進めると手戻りが少なくなります。
- 8.2 で動いている案件を洗い出し、年内に 8.4 か 8.5 へ上げる計画を立てる
session_start()を直接使うコードと、別サイトからの POST を受ける画面を一覧にするmb_ereg系の使用箇所を探し、preg_*へ置き換えてテストする- RC イメージでテストを走らせ、非推奨の警告を一覧にして直す
- 主要な依存パッケージとホスティングが 8.6 に対応してから、本番を上げる
まとめ
- 8.6 は 2026 年 11 月 19 日リリース予定。ただし先に手を打つべきは、年末にサポートが切れる 8.2 の案件です。
- セッション Cookie の既定値が安全側に変わります。素の PHP のセッションで、別サイトからの POST を受けるサイトは要確認です。
mb_ereg系は非推奨になりました。日本語処理のコードを中心に、preg_*+u修飾子への置き換えを進めましょう。
この記事のコード例は RFC と UPGRADING の記述にもとづくもので、正式版で細部が変わる可能性があります。リリース後は、php.net の公式の移行ガイドもあわせて確かめてください。
参考リンク
- PHP 8.6 UPGRADING(php-src、PHP-8.6 ブランチ)
- PHP 8.6 リリース日程(PHP Wiki)
- Supported Versions(php.net)
- RFC: Session security defaults
- RFC: EOL Oniguruma(mbregex の非推奨)
- RFC: Deprecations for PHP 8.6
- RFC: Partial Function Application v2
- RFC: Readonly property defaults
- RFC: Duration class
- php(Docker Official Image)