ユーザーレベルの出力バッファ
ユーザレベルの出力バッファは、
PHP コードから開始、操作、終了することができます。
バッファは、出力バッファと関連する出力ハンドラ関数を含みます。
どの出力をバッファするのか?
PHP のユーザレベル出力バッファは、
起動した後から、バッファリングをオフにするか、
スクリプトが終わるまでのすべての出力をバッファリングします。
PHP のユーザーレベル出力バッファにおける出力とは、
PHP が表示したりブラウザに送り返したりするすべてのものを指します。
実用的な用語で説明すると、出力とは以下に示す、
長さがゼロでないデータのことです:
stdout に直接書き込まれたり、
同様の機能を持つ SAPI 関数に渡されたデータは、
ユーザレベルの出力バッファには取り込まれません。
これに該当するのは、
fwrite を使って stdout
にデータを書き込む場合や、header や
setcookie を使ってヘッダを送信する場合です。
出力バッファをオンにする
出力バッファリングは、&php.ini; 設定
output_buffering
と output_handler
を設定するか、ob_start 関数を使うことでオンにできます。
これらは両方、出力バッファを生成できますが、
ob_start の方がより柔軟です。
なぜなら、出力ハンドラをユーザー定義関数として受け入れますし、
(フラッシュ、クリーン、削除 のような)
バッファに対する操作もできるからです。
ob_start で開始したバッファは、
それをコールした行からアクティブになりますが、
output_buffering
を使って開始したバッファは、スクリプトの最初の行から、出力をバッファします。
PHP は組み込みの
"URL-Rewriter"
出力ハンドラをバンドルしています。
このハンドラは、自分の出力バッファを開始します。
同時に実行できるのはふたつです(1つはユーザレベルのURL書き換えと、
透過的なセッションIDサポートのためのもの) 。
これらのバッファは、output_add_rewrite_var
関数をコールするか、&php.ini; 設定
session.use_trans_sid
を有効にすることで開始できます。
バンドルされている zlib 拡張モジュールは、
独自の出力バッファを持っています。
この出力バッファは、&php.ini; 設定
zlib.output_compression
を使うことで有効にできます。
一度に二つまでしか実行できないという意味で、
"URL-Rewriter" は特別です。
しかし、すべてのユーザレベルの出力バッファは、
カスタムの出力ハンドラ関数を指定して ob_start
をコールすることで開始した既存のバッファと同じものを使います。
そのため、すべての機能はユーザランドのコードでエミュレートすることができます。
出力バッファをネストさせる
新しいバッファが開始されたときに、既にアクティブな出力バッファがある場合、
新しいバッファは、以前にアクティブだったバッファの内部にネストされます。
ネストされたバッファは、ネストされているかどうかに関係なく同じ動作をしますが、
ネストされたバッファによってバッファリングされた出力は、
以前にアクティブだった外側のバッファにはバッファリングされません。
ネストされたバッファからフラッシュされた出力のみが、
外側のバッファによってバッファリングされます。
ほとんどの ob_*
関数は、アクティブな出力バッファ(最後に開始されたもの)に対してのみ動作するため、
アクティブなバッファのみをフラッシュ、クリーン、オフにすることができます。
それ以外のバッファに対して動作する関数は、
使用中のすべての出力ハンドラのリストを返す
ob_list_handlers や、
アクティブなバッファや使用中のすべてのバッファに関する情報を返すことができる
ob_get_status があります。
ob_get_level
や ob_get_status
をコールすると、アクティブな出力バッファのネストレベルを返します。
ob_get_level
と ob_get_status
が指す、同じレベルの値は1つずれています。
ob_get_level では最初のレベルは
1 であるのに対し、
ob_get_status の最初のレベルは
0 になります。
バッファサイズ
バッファサイズは整数で表され、
バッファがフラッシュせずに格納できるバイト数を表します。
バッファ内の出力サイズがバッファサイズを超えると、
バッファの内容が出力ハンドラに送られ、
その戻り値がフラッシュされ、バッファがクリアされます。
"URL-Rewriter" を除いて、
出力バッファのサイズはバッファの開始時に設定することができます。
0 に設定すると、
出力バッファのサイズは PHP が使用可能なメモリの量に制限されます。
1 に設定すると、
0 より大きい長さの出力を生成するコードブロックの後にバッファがフラッシュされます。
出力バッファのサイズは、
ob_get_status をコールすることで取得できます。
ob_start で開始された出力バッファのバッファサイズは、
2番目のパラメータ chunk_size
に渡された整数値に設定されます。省略された場合、
0 が設定されます。
ini 設定 output_buffering
が "On" に設定されている場合、
開始された出力バッファのバッファサイズは 0 に設定されます。
バッファサイズより大きな整数を設定した場合、バッファサイズはその値になります。
"URL-Rewriter" のバッファサイズは
0 に設定されているため、
PHP が使用可能なメモリの量に制限されます。
zlib の出力バッファのサイズは、
&php.ini; の
zlib.output_compression
で設定します。
"On"
に設定すると、バッファサイズは "16K"/16384
になります。
バッファサイズより大きな整数を設定した場合、
バッファサイズはそのバイト数になります。
バッファに対して可能な操作
バッファに対して可能な操作は、
出力バッファの制御フラグ
のいずれかを ob_start の3番めの
flags パラメータに渡すことで制御できます。
省略した場合、すべての操作がデフォルトで許可されます。
0 を指定すると、
バッファのフラッシュ、クリーン、削除はできませんが、
その内容を取得することはできます。
PHP_OUTPUT_HANDLER_CLEANABLE を指定すると、
ob_clean によってバッファの内容を削除できるようになります。
PHP_OUTPUT_HANDLER_CLEANABLE フラグ
を指定していなくても、
ob_end_clean や ob_get_clean
がバッファの内容を削除できなくなるわけではありません。
PHP_OUTPUT_HANDLER_FLUSHABLE を指定すると、
ob_flush を使ってバッファの内容をフラッシュできるようになります。
PHP_OUTPUT_HANDLER_FLUSHABLE フラグ
を指定していなくても、
ob_end_flush や ob_get_flush
がバッファの内容をフラッシュできなくなるわけではありません。
PHP_OUTPUT_HANDLER_REMOVABLE を指定すると、
ob_end_clean, ob_end_flush,
ob_get_clean, ob_get_flush
を使ってバッファをオフにすることができるようになります。
PHP_OUTPUT_HANDLER_STDFLAGS
は、既に述べた3つのフラグの組み合わせで、
指定するとバッファに対する3つの操作を実行できます。
バッファの内容をフラッシュ/アクセス/削除する
フラッシュは、アクティブなバッファの内容を送信し、破棄します。
出力バッファは、出力のサイズがバッファのサイズを超えたときか、
スクリプトが終了するか、
ob_flush, ob_end_flush,
ob_get_flush
のいずれかがコールされたときにフラッシュされます。
ob_end_flush や ob_get_flush
をコールすると、アクティブなバッファがオフになります。
バッファをフラッシュすると、
出力バッファの戻り値がフラッシュされますが、
この値はバッファの内容と異なる場合があります。
例えば、ob_gzhandler
を使うと、出力が圧縮され、圧縮された出力がフラッシュされます。
アクティブなバッファの内容は
ob_get_contents, ob_get_clean,
ob_get_flush をコールすると取得できます。
バッファの中身の長さだけが必要な場合、
ob_get_length や ob_get_status
を使えばバッファの中身の長さをバイト単位で取得できます。
ob_get_clean や ob_get_flush
をコールすると、アクティブなバッファの中身を返した後、
そのバッファをオフにします。
アクティブなバッファの中身は、
ob_clean, ob_end_clean,
ob_get_clean を使って削除できます。
ob_end_clean や ob_get_clean
を使うと、アクティブなバッファがオフになります。
出力バッファをオフにする
ob_end_clean, ob_end_flush,
ob_get_flush, ob_get_clean
をコールすると、出力バッファをオフにできます。
PHP_OUTPUT_HANDLER_REMOVABLE
を指定せずに起動した出力バッファはオフにできず、
E_NOTICE が発生します。
スクリプトの終了時、または exit
がコールされるまでに閉じられていないすべての出力バッファは、
PHP のシャットダウン処理によってフラッシュされ、オフになります。
バッファは、起動した順序と逆の順序でフラッシュされ、オフになります。
最後にバッファリングが開始されたものが最初になり、
最初にバッファリングが開始されたものが最後にフラッシュされ、オフになります。
バッファの内容をフラッシュしたくない場合は、
カスタムの出力ハンドラを使い、シャットダウン中のフラッシュを防ぐべきです。
出力ハンドラ
出力ハンドラは、出力バッファに関連付けられた callable です。
ob_clean,
ob_flush, ob_end_flush,
ob_get_flush, ob_end_clean,
ob_get_clean をコールすると呼び出されます。
また、PHP のシャットダウン処理中にも呼び出されます。
シャットダウン処理は、ハンドラの戻り値をフラッシュします。
出力バッファを開始するときに、ハンドラを省略したり &null; を指定した場合、
内部的な "default output handler"
が使われます。このハンドラは、呼び出された際にバッファの内容を変更せずに返します。
出力ハンドラは、バッファの内容を変更 かつ/または 副作用(例:ヘッダの送信)
をもたせるために使うことができます。
PHP には、内部的な出力ハンドラをふたつ持っています:
"default output handler"
と "URL-Rewriter"
(これは独自の出力バッファに統合されており、2つまでしか起動できません)
がそうです。
PHP 本体にバンドルされている拡張モジュールには、
追加の出力ハンドラが4つあります:
mb_output_handler, ob_gzhandler,
ob_iconv_handler, ob_tidyhandler です。
出力ハンドラを扱う
出力ハンドラが呼び出されると、
バッファの内容と、出力バッファリングの状態を示すビットマスクが渡されます。
string
handler
string
buffer
int
phase
buffer
出力バッファの内容
phase
PHP_OUTPUT_HANDLER_*
定数
のビットマスク
出力ハンドラの内部で以下の関数をコールすると、致命的なエラーが発生します:
ob_clean, ob_end_clean,
ob_end_flush, ob_flush,
ob_get_clean, ob_get_flush,
ob_start
ハンドラの PHP_OUTPUT_HANDLER_DISABLED
が設定されている場合、
ob_end_clean, ob_end_flush,
ob_get_clean, ob_get_flush
ob_clean, ob_flush
をコールしてもハンドラは呼び出されません。
PHP のシャットダウン処理中でも同様です。
PHP 8.4.0 より前のバージョンでは、
ob_clean
をコールしてもこのフラグは何の効果もありませんでした。
一部のウェブサーバー、例えば Apache やビルトイン・ウェブサーバーでは、
作業ディレクトリがシャットダウン中に変更される場合があります。
出力ハンドラに渡されるフラグ
出力ハンドラの2つめの phase
パラメータに渡されるビットマスクは、
ハンドラの起動に関する情報を提供します。
ビットマスクは複数のフラグを含むことができるので、
フラグがセットされているかどうかをチェックするには、
ビット演算子 & を使う必要があります。
PHP_OUTPUT_HANDLER_WRITE と、そのエイリアス
PHP_OUTPUT_HANDLER_CONT
の値は 0 です。
よって、これらの値が設定されているかを調べられるのは
比較演算子
(== or ===) だけです。
ハンドラのライフサイクルの特定のフェーズで、以下のフラグが設定されます:
PHP_OUTPUT_HANDLER_START
は、ハンドラが初めて起動されたときに設定されます。
PHP_OUTPUT_HANDLER_FINAL
やそのエイリアス PHP_OUTPUT_HANDLER_END
はハンドラが最後に起動されるとき、
つまりハンドラがオフになるときに設定されます。
PHP のシャットダウン処理によってバッファがオフにする際にも設定されます。
ハンドラの特定の呼び出しに応じて、以下のフラグが設定されます:
PHP_OUTPUT_HANDLER_FLUSH は、
ob_flush をコールしてハンドラが呼び出された際に設定されます。
PHP_OUTPUT_HANDLER_WRITE
やそのエイリアス PHP_OUTPUT_HANDLER_CONT
は、バッファの内容の長さがバッファのサイズ以上かつ、
バッファが自動的にフラッシュされている間にハンドラを起動したときに設定されます。
PHP_OUTPUT_HANDLER_FLUSH は、
ob_clean,
ob_end_clean や ob_get_clean
をコールしてハンドラが呼び出された場合に設定されます。
ob_end_clean や ob_get_clean
がコールされた場合は、PHP_OUTPUT_HANDLER_FINAL
も同時に設定されます。
ob_end_flush や ob_get_flush
がコールされると、PHP_OUTPUT_HANDLER_FINAL
が設定されますが、PHP_OUTPUT_HANDLER_FLUSH
は設定されません。
出力ハンドラの戻り値
出力ハンドラの戻り値は、
以下に示す PHP の標準的な型のセマンティクスに従って文字列に自動変換されますが、
ふたつだけ例外があります: array と bool です。
配列は文字列 "Array"
に変換されますが、警告 Array to string conversion
は発生しません。
ハンドラが &false; を返した場合、
バッファの内容が返されます。
ハンドラが &true; を返した場合、
空文字列が返されます。
ハンドラが &false; を返したり、ハンドラで例外が発生した場合、
PHP_OUTPUT_HANDLER_DISABLED フラグが設定されます。
出力ハンドラでスローされる例外
捕捉されない例外が出力ハンドラでスローされた場合、
プログラムは終了し、"Uncaught Exception"
エラーメッセージがフラッシュされた後に、
シャットダウン処理によってハンドラが呼び出されます。
ob_flush,
ob_end_flush, ob_get_flush
が呼び出したハンドラが、捕捉されない例外をスローした場合、
エラーメッセージがフラッシュされる前にバッファの内容がフラッシュされます。
シャットダウン処理中に出力ハンドラが捕捉されない例外をスローした場合、
ハンドラは終了し、バッファの内容もエラーメッセージもフラッシュされません。
ハンドラが例外をスローした場合、
PHP_OUTPUT_HANDLER_DISABLED
フラグが設定されます。
出力ハンドラで発生したエラー
出力ハンドラで致命的でないエラーが発生した場合、
プログラムの実行は継続されます。
ob_flush, ob_end_flush,
ob_get_flush
が呼び出したハンドラで致命的でないエラーが発生した場合、
ハンドラの戻り値に応じて、バッファは一定のデータをフラッシュします。
ハンドラが &false; を返す場合、
バッファの中身とエラーメッセージがフラッシュされます。
それ以外の値をハンドラが返す場合、
ハンドラの戻り値はフラッシュされますが、エラーメッセージはフラッシュされません。
ハンドラが &false; を返す場合、
PHP_OUTPUT_HANDLER_DISABLED フラグが設定されます。
出力ハンドラ中で致命的なエラーが発生した場合、
プログラムは終了し、
エラーメッセージがフラッシュされた後に、
シャットダウン処理によってハンドラが呼び出されます。
ob_flush,
ob_end_flush, ob_get_flush
が呼び出したハンドラで、致命的なエラーが発生した場合、
エラーメッセージがフラッシュされる前にバッファの内容がフラッシュされます。
シャットダウン処理中に出力ハンドラで致命的なエラーが発生した場合、
プログラムは終了し、バッファの内容もエラーメッセージもフラッシュされません。
出力ハンドラで行われた出力
特定の状況下では、
ハンドラ内で生成された出力はバッファの内容と共にフラッシュされます。
この出力はバッファに追加されず、
ob_get_flush が返す文字列の一部にもなりません。
フラッシュの操作中
(ob_flush,
ob_end_flush, ob_get_flush
のコール中、またはシャットダウン処理中)に、
ハンドラが &false; を返した場合、
バッファの内容がフラッシュされ、その後に出力が行われます。
シャットダウン処理中にハンドラが呼び出されなかった場合、
ハンドラが例外をスローするか、exit が呼び出されると、
同じ動作になります。
ハンドラが &false; を返した場合、
PHP_OUTPUT_HANDLER_DISABLED が設定されます。
出力ハンドラのステータスフラグ
バッファが持つ flags ビットマスクの
出力ハンドラのステータスフラグ は、
出力ハンドラが起動されるたびに設定され、
ob_get_status が返す flags
の一部になります。
ハンドラが正常に実行され、&false; を返さなかった場合、
PHP_OUTPUT_HANDLER_STARTED と
PHP_OUTPUT_HANDLER_PROCESSED が設定されます。
ハンドラが &false; を返すか、実行中に例外がスローされた場合は、
PHP_OUTPUT_HANDLER_STARTED と
PHP_OUTPUT_HANDLER_DISABLED が設定されます。
ハンドラの PHP_OUTPUT_HANDLER_DISABLED
が設定されている場合、
ob_end_clean, ob_end_flush,
ob_get_clean, ob_get_flush
ob_clean, ob_flush
経由でハンドラは呼び出されません。
PHP のシャットダウン処理中でも同様です。
PHP 8.4.0 より前のバージョンでは、
ob_clean や ob_flush
をコールしてもこのフラグはなんの意味もありませんでした。