1 of 19

"今のまま" PHP サーバーを高速化する� PHP 8.6 に向けた�"OPcache Static Cache"�RFC について

PHP Conference 2026 / Go Kudo (@zeriyoshi)

PHP Conference 2026 / opcache_static_cache, user_cache / Go Kudo (@zeriyoshi) Track #1

1

2 of 19

アジェンダ

  • PHP の動作形態と仕組み
  • PHP とキャッシュの現状
  • “colopl_cache” について
  • “colopl_xcache” について
  • “OPcache Static Cache” について
  • “OPcache User Cache”, そして “ext-user_cache” へ...
  • “colopl_xcache” の詳細とこれから
  • まとめと反省点

PHP Conference 2026 / opcache_static_cache, user_cache / Go Kudo (@zeriyoshi) Track #1

2

3 of 19

PHP の仕組みについて

PHP Conference 2026 / opcache_static_cache, user_cache / Go Kudo (@zeriyoshi) Track #1

3

4 of 19

PHP の動作形態と仕組み

PHP は現状、だいたい以下のどれかの方法で動いている。�これらは SAPI (Server-side API) とも呼ばれる (サーバーではなくともそう呼ばれる)

  • CLI
    • php コマンドで実行される。 Laravel などでは Artisan 等を実行したりなど
    • ビルトインサーバーもあるので簡易動作確認にも使われる
  • FastCGI Process Manager (fpm)
    • 現状最も一般的? nginx 等と組み合わせて使用
  • Apache2Handler (mod_php / apxs2handler)
    • Apache HTTP Server 上ではよく利用されている

一方で、最近ではちょっと変わった実行方法も増えてきている (これは後述)

  • FrankenPHP
  • Swoole
  • RoadRunner
  • etc…

PHP Conference 2026 / opcache_static_cache, user_cache / Go Kudo (@zeriyoshi) Track #1

4

5 of 19

PHP の動作形態と仕組み

PHP は基本的にシェアードナッシング型アーキテクチャで動作している

つまり、リクエストを処理する際に初期化したメモリやリソースなどは static だろうと�リクエスト終了ごとに破棄され、次のリクエストで生成しなおされる

PHP Conference 2026 / opcache_static_cache, user_cache / Go Kudo (@zeriyoshi) Track #1

5

Request1 End

Zend Engine + Extension

Request1 Start

Free

Zend Engine + Extension

Request1 Working Memory

Free

Request2 Start

Zend Engine + Extension

Free

Request2 End

Zend Engine + Extension

Request2 Working Memory

Free

6 of 19

シェアードナッシング型アーキテクチャのメリット・デメリット

シェアードナッシング型の PHP サーバー

メリット

  • メモリ管理を意識しなくていい
  • ガベージコレクションが起きにくい

デメリット

  • データはリクエスト境界を跨げない
  • キャッシュ面で圧倒的に不利

他言語などの通常の Web サーバー

メリット

  • リクエスト跨ぎでデータを維持できる
  • キャッシュの仕組みが作りやすい

デメリット

  • 意図しないメモリリークが起こりうる
  • ガベージコレクション多発の可能性

PHP Conference 2026 / opcache_static_cache, user_cache / Go Kudo (@zeriyoshi) Track #1

6

7 of 19

シェアードナッシングの実例

PHP において、次のコードは何度リクエストを受けても 1 しか返さない

<?php declare(strict_types=1);

final class Foo {

public static int $counter = 0;

}

echo ++Foo::$counter, \PHP_EOL;

// 一生 1 しか返さない

PHP Conference 2026 / opcache_static_cache, user_cache / Go Kudo (@zeriyoshi) Track #1

7

8 of 19

PHP のキャッシュの現状

現状、 PHP は基本的にシェアードナッシング型アーキテクチャで動作しており�言語機能単体ではリクエストを跨ぐキャッシュを実現する手段がない

よく使われる回避策:

  • ext-apcu の利用
    • よく見る事例。共有メモリを作成し値を serialize / unserialize して入れておく
    • 豆知識: シリアライザに ext-igbinary を利用すると効率がかなり良くなる
  • Redis や memcached の利用
    • volatile (揮発性) でいいものを入れるのに使ったり
    • とはいえ、通信のオーバヘッド・ serialize / unserialize のオーバーヘッドがある
  • OPcache preload を用いた固定データの preload
    • 静的配列 (すべてがスカラ値で表される配列) をそのままキャッシュできる
  • “常時実行型 PHP ランタイム” の利用
    • FrankenPHP や Swoole 等の常時実行型ランタイムを用いてこれを回避する
    • Swoole には SwooleTable というキャッシュの仕組みがある

PHP Conference 2026 / opcache_static_cache, user_cache / Go Kudo (@zeriyoshi) Track #1

8

9 of 19

PHP のキャッシュの現状

今一番筋が良い解決方法は OPcache preload による静的配列のプリローディングか�Swoole と SwooleTable を用いたキャッシュを利用すること

一方で、 “常時実行型 PHP ランタイム” は殆どの場合において既存のコードベースをそのまま移植することは難しい (Larvel なら singletonscoped に変えるなど対応が必要、 FrankenPHP はリクエスト持ち越しができてもそれは worker ごとなので、結局完全な一つのキャッシュは実現できない�(ただし、実装完了したはずなので次のリリースから使えそう)

何より、シェーアドナッシングアーキテクチャありきで書かれた古いコードベースを常時実行型 PHP に移行するハードルはとてつもなく高い

じゃあ、より速い APCu を作れば良いのでは?

PHP Conference 2026 / opcache_static_cache, user_cache / Go Kudo (@zeriyoshi) Track #1

9

10 of 19

“colopl_cache” について

もっと速い APCu を、と PHP コードベースの調査を始め、某社社内で作成していた内製�PHP Extension

基本戦略はこうだった:

  • スカラ値、 OPcache でいう静的配列はそのまま SHM (共有メモリ) に格納する
  • ext-igbinary はポータビリティを重視していたが、それを無視してハードウェアの�メモリアライメントに最適化した独自のバイナリ形式でシリアライズ・デシリアライズする
  • デシリアライズ時、トップレベルオブジェクト以外はアクセスされたときに初めてデシリアライズ (ハイドレーション) するようにする (Lazy hydrate)

結果: あんまり意味なかった

PHP Conference 2026 / opcache_static_cache, user_cache / Go Kudo (@zeriyoshi) Track #1

10

11 of 19

“colopl_cache” について

敗因

  • そもそも根本的な問題は PHP エンジン側のデシリアライズの重さだった
    • __unserialize を呼ぶ以上、速度向上は殆ど見込めない
  • Lazy hydrate したはいいが、アクセスしてないプロパティなどなかった
    • 結局 Lazy hydrate の判定をする処理のほうが重くなってしまった
  • スカラ値のダイレクトコピーは APCu 側で既に対応されていた
    • 一方で、静的配列では大きく効果が出た。が、すべての要素がスカラ値な配列など殆ど使っておらず、効果が発揮できなかった

じゃあどうしようか...

PHP Conference 2026 / opcache_static_cache, user_cache / Go Kudo (@zeriyoshi) Track #1

11

12 of 19

“colopl_xcache” について

戦略レベルで考え直し、 “そもそもシリアライズを無くす” を目標にすることに

戦略:

  • ユーザー定義オブジェクトは共有グラフ表現にすることで SHM (共有メモリ) にダイレクトに格納・復元できるように
    • 共有グラフ表現: ポインタ参照先やらなんやらを相対的なものにし、ひとかたまりとして扱えるようにしたもの
  • 組み込みクラスはネイティブ実装されているため通常共有グラフ化できないが、そのバージョンの PHP における内部構造はコードからわかるのでそれをベースに無理やり共有グラフ化するためのコードを記述し、一部オブジェクトを共有グラフ化できるように
  • Attribute を新設し、その Attribute がついたクラス・メソッド・プロパティの static 値は常にキャッシュするように

結果: DateTime を含むモデルがめちゃくちゃ速くなった

PHP Conference 2026 / opcache_static_cache, user_cache / Go Kudo (@zeriyoshi) Track #1

12

13 of 19

“colopl_xcache” について

共有グラフ戦略はいけると確信、ただ障壁が見えてきた

  • PHP 組み込みクラスはメモリ構造が opaque pointer で表されており、コンパイル時にも参照できないので拡張側でメモリ構造を二重に持つのは不毛かつ危険
  • Carbon は DateTime を継承しているがユーザークラスであり __unserialize で自身の spl_object_hash を管理しているので共有グラフから復元しただけだと (殆ど踏まないが) 内部的には不整合を起こした状態になる
  • PHP のバージョンアップに追従していくのが苦痛すぎる

もうこれは PHP 本体に入れてもらったほうがいいのでは... (既視感)

PHP Conference 2026 / opcache_static_cache, user_cache / Go Kudo (@zeriyoshi) Track #1

13

14 of 19

OPcache Static Cache について

PHP RFC として “OPcache Static Cache” を提案した

https://wiki.php.net/rfc/opcache_static_cache

https://externals.io/message/130912

中身は基本的に colopl_xcache をエンジンネイティブにし、かつ OPcache に統合することで JIT 利用時も Attribute を適切に扱えるようにしたもの

いつもの私の悪い癖: どうせ PHP 本体に入れてもらいたいのだから、と、 JIT での高速化まで取り入れ、変更規模を大きくしすぎた

結果:�レビューコストが大きすぎる。 OPcache に手を入れるのはかなり慎重にならざるを得ないし、 JIT はなおさら。また API 設計が適切でなく、かつ VolatileCache や StaticCache など新たな概念を導入したせいで feature creep となり厳しい状況に...

PHP Conference 2026 / opcache_static_cache, user_cache / Go Kudo (@zeriyoshi) Track #1

14

15 of 19

OPcache User Cache について

実はこれは表には出ていない

OPcache Static Cache から以下の点を改良した

  • API の明瞭化
  • Attribute 機能の名称変更
  • SAPI セキュリティ境界の問題を修正
  • パフォーマンスの改善

が、そもそも継ぎ足し継ぎ足しで作っていたのでもはや自分でもわけがわからなくなってきたので、一旦そのものを破棄した

PHP Conference 2026 / opcache_static_cache, user_cache / Go Kudo (@zeriyoshi) Track #1

15

16 of 19

user_cache について

戦略だけを残し、フルスクラッチで作り直したもの。 OPcache の一部ではなく、 user_cache という名の全く新しい拡張機能

変更点

  • JIT 介入と Attribute をやめたので、別 Extension として新規作成
  • API をよりわかりやすくし、各 SHM (共有メモリ) のプール分離をより厳格化
  • 共有グラフとシリアライザをハイブリッド化し、共有グラフで扱える部分は共有グラフで、それ以外はシリアライザに落とすように
    • キャッシュなので store 性能は割り切り、より fetch 性能に寄せた
      • おかげで fetch では APCu + igbinary に負けるパターンはゼロに

RFC: https://wiki.php.net/rfc/impl_user_cache

大問題: これが完全新規の RFC とみなされるのなら、 PHP 8.6 にはもう間に合わない!

PHP Conference 2026 / opcache_static_cache, user_cache / Go Kudo (@zeriyoshi) Track #1

16

17 of 19

“colopl_xcache” の詳細とこれから

ext-user_cache を PHP 8.1 ~ 8.6-dev まで用にバックポートし、改めて ext-colopl_xcache�として作成

現状ベンチマークハーネスにかけている限り速度もかなり良好

もしかしたらどこかの会社のオープンソースソフトとして公開されるかもしれない...�(本当に未定なのでわからない)

PHP Conference 2026 / opcache_static_cache, user_cache / Go Kudo (@zeriyoshi) Track #1

17

18 of 19

まとめ

できるからといって feature creep になるのヨクナイ

ちゃんとそれをレビューする側の気持ちになってみよう。�突然クソデカ PR 投げられたら相手がどう思うかちゃんと考えよう。

現実のワークロードをよく考えよう

Lazy hydrate など当初は画期的だと思ったが、そもそもアクセスしないものをキャッシュから引いてくるわけがなく、根本的に発想が悪かった。�ちゃんと PHP の実装をよく読み、共有グラフの道を最初から見つけるべきだった。

入ったとしてもPHP 8.7 になっちゃうかもです。すみません...

前述の通り RFC の扱われ方によっては 8.6 の Feature Freeze に間に合わない算段が高く�その場合は 8.7 、あるいは 9.0 になる可能性が高いです...�

PHP Conference 2026 / opcache_static_cache, user_cache / Go Kudo (@zeriyoshi) Track #1

18

19 of 19

ご清聴ありがとうございました

Questions to: @zeriyoshi (X/Twitter)

PHP Conference 2026 / opcache_static_cache, user_cache / Go Kudo (@zeriyoshi) Track #1

19