はじめに
PHP8上級試験の問題集を進めていると、Phar
アーカイブや __halt_compiler()
に関する問題が出てきます。普段の開発ではなかなか触れる機会が少ないため「何をしているの?」と混乱しやすいポイントです。
この記事では、試験に登場する次のコード例をベースに、__halt_compiler()
と__COMPILER_HALT_OFFSET__
の動きを整理します。
目次
サンプルコード
<?php
declare(strict_types=1);
error_reporting(-1);
var_dump(__COMPILER_HALT_OFFSET__);
$data = file_get_contents(filename:__FILE__, offset:__COMPILER_HALT_OFFSET__);
var_dump($data);
__halt_compiler();
set data;
write data i ACED.
実行結果
int(205)
string(29)
" set data;
write data i ACED."
解説
__halt_compiler()
- PHP の コンパイル処理をそこで終了 させる特殊関数です。
- この行以降に書いたテキストは「PHPコード」ではなく「生データ」としてファイルに保存されます。
exit
やdie
のように「実行を止める」わけではなく、「これ以上コードをコンパイルしない」 という動作をするのがポイントです。
COMPILER_HALT_OFFSET
__halt_compiler()
が登場した位置(=ファイル内のバイトオフセット値)を保持する定数です。- これを利用すると「ファイルのどこからがデータ領域なのか」を知ることができます。
今回の例では 205
という値が返ってきています。つまり、ファイルの 205 バイト目以降は 任意データ領域 です。
file_get_contents(FILE, offset: COMPILER_HALT_OFFSET)
- 実行中のファイル (
__FILE__
) を読み込みます。 offset
を指定することで「205バイト目以降(__halt_compiler の直後)」だけを取得しています。- そのため、出力は
set data; write data i ACED.
という埋め込んだ文字列になるわけです。
まとめ
__halt_compiler()
… コンパイルを中止して、以降を「データ領域」とする。__COMPILER_HALT_OFFSET__
… そのデータ領域の開始位置(バイトオフセット)。file_get_contents(__FILE__, offset: …)
で自分自身のファイルを読み込むと、埋め込みデータを取り出せる。
この仕組みは Phar
アーカイブの「起動スタブ」に必須で、試験でもよく問われるポイントです。
普段の開発では触れなくても、理解しておくと「PHP がどうやって Phar を扱っているのか」が見えてきます。