PHPは、インタプリタです。
すなわち、リクエストがあるたびに毎回PHPのソースコードを読み取って、オペコードに変換して、ネイティブコードに変換して、実行して、そして実行が終わったら結果を全て捨てます。
そんな仕様なので、コンパイル言語に比べると、変更をコンパイルなしで即時反映できるといった多くのメリットと引き換えに、実行速度が遅いというハンデがあります。
開発者の努力によって相当な高速化がなされていることも事実ですが、それでも言語仕様の壁は乗り越えられません。
従ってPHPにもコンパイル言語のメリットを取り入れたいとう話は当然あがるわけで、実際にだいぶ昔からその機能が存在します。
具体的にはOPcacheで、これはPHPのソースコードを変換した後のオペコードを保存しておいて、次のリクエストにも使い回す仕組みです。
PHPによるコード解析処理をまるまるすっ飛ばせるので、規模によっては相当な高速化が見込めます。
たとえばLaravelはOPcache最適化されているらしく、有効化するだけで5倍とか10倍とか景気のいい速度向上が見込めるようです。
またPHP8.0からはOPcacheの一機能としてJITが導入されました。
これはネイティブコードを保存しておいて次のリクエストにも使い回す仕組みです。
OPcacheよりさらに高速化しますが、そのぶん開発もだいぶ難しいらしく、JITのバス係数は1です。
とまあ非常に効果が高い機能であり、開発者も大変力をいれており、opcache.enable=1
って書くだけで使えるので常に使っていきたいところです。
ところが、実はOPcacheはオプションです。
すなわち、インストールしないことが可能です。
ということで、OPcacheをインストールできないようにしないようにするRFCが提出されました。
既に受理されており、PHP8.5以降OPcacheはprintやfile_get_contentsなどと同様、常に存在する機能となります。
以下は該当のRFC、Make OPcache a non-optional part of PHPの紹介です。
PHP RFC: Make OPcache a non-optional part of PHP
Introduction
OPCacheは、PHP5.5でPHPに統合されて以来、PHPに欠かせない要素になっています。
OPCacheを有効にせず本番環境を展開することは一般的に間違いとみなされ、あらゆる新機能はOPCacheと互換性があることが前提とされています。
しかし、OPCacheはPHPに不可欠であるにもかかわらず、いまだPHPのオプション扱いです。
たとえばPHPオフィシャルのDockerイメージはOPcacheを明示的にコンパイルしなければならないため、ユーザがOPcacheなしで実行してしまう可能性が高くなっています。
またオプションであるせいで、PHPコア機能にはコードパスが2つ存在することになります。
結果としてテスト中に検出することが難しいOPcache固有のバグなどを見逃しやすくなっています。
Proposal
このRFCでは、OPcacheをPHPの必須コンポーネントにすることを提案します。
これによって、OPcacheはext/date
・ext/hash
・ext/pcre
・ext/random
・ext/standard
などと同様静的にコンパイルされます。
このRFCの目的は、OPcacheとZend Engineを緊密に結合し、PHPのメンテナンスを簡素化し、コアエンジンの2種類の実装(OPcacheと、非OPcache)を保守する手間を回避することです。
またZend Engineには既に、OPcacheが有効な場合のみ有効になる機能も含まれており、既にZend EngineとOPcacheの境界は曖昧です。
現在既に頻繁に行われている他の内部リファクタリングと同様、この統合に関する技術的な詳細についてはコア開発者に委ねられています。
具体的には、要求に応じてOPcacheとZend Engine間で機能を移動する可能性があります。
ただし、変更はPHPの後方互換性に従う必要があります。
OPcacheが必須コンポーネントになるということは、ユーザが常にOPcacheの機能を使えるということではありません。
このRFCではopcache.enable
やopcache.enable_cli
といった既存INI設定の削除は提案していません。
OPcacheが常に利用可能であるということは、Optimizerが常に利用可能であることを意味します。
これによって、コア開発者はOptimizerが存在するか否かで最適化ロジックを分けることなく、最適化を常にOptimizerに任せることができます。
Backward Incompatible Changes
互換性のない変更点。
ユーザはOPcacheがロードされていない状態でPHPを使用することができなくなります。
configure
スクリプトからフラグ--disable-opcache
は削除されます。
php.ini
設定からzend_extension=opcache
を削除する必要があります。
Proposed PHP Version(s)
PHP8.5。
RFC Impact
To SAPIs
OPcacheは、サポートされていないAPIの実行時にOPcacheを無効化するためのSAPIホワイトリストを保持しています。
本RFCではOPcacheが常にロードされるようになるだけで、SAPIホワイトリストなど実行時の挙動は変化しません。
To Existing Extensions
エクステンションは、OPCacheが常に存在する前提にすることができます。
To Opcache
Opcacheは必須のエクステンションとなります。
今後新たに提出されるRFCにおいて、『To Opcache』の項目は必要なくなります。
New Constants
新しい定数はありません。
php.ini Defaults
php.ini設定に変更はありません。
Unaffected PHP Functionality
影響を受ける機能は、OPCacheだけです。
Future Scope
このRFCでは、OPCacheを必須とするかだけを提案してします。
具体的にどのように実装されるかは、PHPコア開発者に委ねられます。
Proposed Voting Choices
賛成30反対0の満場一致で可決されました。
Patches and Tests
References
・Opcache optimization without any caching
Opcacheのキャッシュは有効にせず最適化だけを有効にする提案。
最適化だけをPHPコアに移動するという点が注目され、RFCは却下されました。
Opcacheは唯一生き残っているアクセラレータです。
WikipediaによるとWinCacheはメンテナンスされていますが、PHP8には対応していません。
感想
今回の変更は、どちらかというとユーザのためというより開発者のためという面が大きいようです。
エクステンションがインストールされているいないによって内部動作を変えるところはいくつもありますが、OPCacheの場合はシステムの奥深くまで入り込んでいるのに任意インストールだったため、分岐がたいへんつらいことになっているということです。
今回の変更で#ifdef
の山を片付けることが可能になり、ソースコードがすっきりしそうですね。
なお、OPCacheが常にインストールされることと、ユーザがOPCacheを使えることはイコールではありません。
今後もopcache.enable=0
にすれば無効化され、インストールされているけど使えないという状態になります。
しかしこの機能を使えば圧倒的に高速化するわけなので、基本的にオンにしておいて損はないでしょう。
ところでRFCやWikipediaではWinCacheはPHP8未対応って書いてありますが、調べてみたらなんか2024/06/29にPHP8.1-8.4対応版が出ていました。
まあでも公式に優れた機能があるのに、わざわざ外部ライブラリを導入する意義もあんまりなさそうです。