処理系の強化
処理系には、主に高速化を意図した変更が加えられています。
新しいJITコンパイラ
PHP 8.4では、中間表現を用いた新たなJITコンパイラの実装により、コンパイルと実行がより高速になりました。PHPの最適化は8.0から始まりましたが、それはZend仮想マシンのバイトコードから直接ネイティブコードを生成するものでした。これには最適化に制約が加わることになり、これを解決するのが中間表現(IR; Intermediate Representation)です。
中間表現は、IRフレームワークによりプラットフォームに依存しない形で生成され、そこから最適化、レジスタ割り当て、スケジューリング、ネイティブコード生成に移行します。つまり二段構えでPHPコードがネイティブコードに変換されます。
従来のJITに比較して5~10%高速になり、ネイティブコードのサイズは少し小さくなるようです。
JIT無効化の簡便化
PHP 8.4では、JITを無効化する際の設定がより簡便になりました。従来は、以下のリストのようにJITを無効化していました。
opcache.jit=tracing opcache.jit_buffer_size=0 // 無効化の設定
直感的に分かりにくいということで、opcache.jitをdisableに設定するという分かりやすい方法に変わりました。
opcache.jit=disable opcache.jit_buffer_size=64m
なお、これは既定値であるので、特に指定しなければ従来と変わりません。つまり、これまでのアプリには影響を与えません。
問題のある拡張モジュールのアンバンドル化
PHP 8.4では、拡張モジュールimap(IMAP、POP3、NNTPのサポート)、pspell(スペルチェック)、oci8(Oracle OCI8サポート)、pdo_oci(Oracle関数)をバンドルから除外しました。PECLから必要に応じてインストールすることができます。
DOMの機能強化
DOMの利用においても機能が強化されました。
HTML5対応のDOM\HTMLDocument
PHP 8.4では、新しく導入されたクラス\DOM\HTMLDocumentで、HTML5準拠のDOM(Document Object Model)の取り扱いが可能になりました。
これまでは、DOMの操作にはlibxmlによるパーサを利用するしかありませんでしたが、このライブラリはHTML4準拠であるという問題が長い間続いていました。これが、HTML5対応のパーサLexborの導入で、HTML5でも問題なくパースできる環境が整いました。これに合わせて、HTML Living Standard準拠へのDOM対応の修正が実施されています。
以下は、HTML4とHTML5のファイルを用意して読み込んでいる例です(ファイルの全容は配布サンプルを参照)。DOMDocumentクラスのloadメソッドによる読み込みで、HTML4ファイルは問題なく読み込めますが、HTML5ファイルは開始タグと終了タグがマッチしないなどのWarningが発生します。DOM\HTMLDocumentクラスのcreateFromFileでは、HTML5ファイルを問題なく読み込めます。
$dom = new DOMDocument(); $dom->load('html4.html'); // HTML4準拠のファイルでは問題なし $dom->load('html5.html'); // HTML5準拠のファイルではWarning $dom5 = DOM\HTMLDocument::createFromFile('html5.html'); // 問題なし
DOM操作のための関数querySelector/closest/matches
PHP 8.4では、DOM操作のための関数querySelector、closest、matchesが、新しいDOMクラスに用意されました。いずれもJavaScriptにある同名の関数に相当します。
- querySelector:セレクタによる検索
- closest:当該要素から祖先方向に、指定されるセレクタに合致する最初の要素を検索
- matches:当該要素が指定されるセレクタに一致するかチェック
以下のリストは、サンプル確認のためのHTML5ファイルのbody要素内を抜粋したものです。
<div id="root"> <p id="child"><span>p span</span></p> </div>
DOMは、以下のリストのようにcreateFromFile静的メソッドで上記のHTML5ファイルを直接読み込んで構築できます。
$dom5 = DOM\HTMLDocument::createFromFile('html5.html'); var_dump($dom5->querySelector('p span')->textContent); // string(6) "p span" var_dump($dom5->getElementById('child')->closest('div')->getAttribute("id")); // string(8) "root" var_dump($dom5->getElementById('root')->matches('body > div')); // bool(true)