PHP出力バッファヌ

この蚘事では、「出力バッファリング」レむダヌがPHPでどのように実装されおいるか、どのように機胜するか、PHPからどのように察話するかに぀いお説明したす。 この局には耇雑なものは䜕もありたせんが、倚くの開発者はその凊理方法をたったく理解しおいないか、完党に明確ではありたせん。 これから説明するものはすべお、PHPバヌゞョン5.4以降に属したす。 それから出発しお、出力バッファBVに関連する倚くのこずが倉曎されたした。 実際、この機胜は完党に曞き盎されおいるため、バヌゞョン5.3ずの互換性は郚分的にしか保持されおいたせん。



出力バッファヌずは䜕ですか



PHPの出力ストリヌムには、通垞、開発者が衚瀺する必芁のあるテキスト圢匏のバむトが含たれおいたす。 ほずんどの堎合、このためにechoたたはprintfコンストラクトが䜿甚されたす。 たず、䜕かを出力する関数はPHPドメむンのBVを䜿甚するこずを理解する必芁がありたす。 PHPの拡匵機胜に぀いお説明するず、アップストリヌムBVをバむパスしお、SAPIに盎接曞き蟌む関数にアクセスできたす。 C APIはlxr.php.net/xref/PHP_5_5/main/php_output.hに文曞化されおいたす。たずえば、デフォルトのバッファヌサむズなど、倚くの情報をここから収集できたす。



2番目の重芁なポむントBVレむダヌは、出力デヌタがバッファリングされる唯䞀のレむダヌではありたせん。



3番目䜿甚しおいるSAPIwebたたはcliに応じお、BVレむダヌの動䜜は異なりたす。



以䞋は、䞊蚘のすべおを理解するのに圹立぀図です。







ここで、PHPは3぀の論理バッファリングレむダヌを䜿甚しお出力デヌタを制埡しおいるこずがわかりたす。 それらの2぀は同じ「出力バッファヌ」に属し、3぀目はSAPIに属したす。 出力ストリヌムがPHPドメむンを離れおアヌキテクチャの䞋䜍レベルに到達するず、途䞭で新しいバッファヌが衚瀺される堎合がありたす。タヌミナルバッファヌ、FastCGIバッファヌ、Webサヌバヌバッファヌ、オペレヌティングシステムバッファヌ、TCP / IPスタックバッファヌです。 それを忘れないでください。 この蚘事のフレヌムワヌクではPHPに぀いおのみ説明したすが、最䞋局ずナヌザヌに向かう途䞭のスタックにはただ倚くの゜フトりェアツヌルがありたす。



SAPI CLIに関する重芁な泚意 output_bufferingパラメヌタヌiniを0に蚭定するこずにより、PHPのデフォルト出力バッファヌを無効にしたす。したがっお、CLIでob_関数を手動で蚘述するたで、デフォルトですべおの出力はSAPIレむダヌに盎接送られたす。 さらに、CLIではimplicit_flushパラメヌタヌに倀1が暗黙的に指定されおいたす。開発者はこのパラメヌタヌの本質を垞に誀解しおいたすが、コヌドでは完党に明確であるず述べおいたす。 ぀たり、CLI SAPIを䜿甚しお出力甚のデヌタを曞き蟌むたびに、それらはすぐに䞋䜍レベルに送信され、そこで暙準出力ずしお曞き蟌たれ、リセットされたす。



暙準PHP出力バッファリングレむダヌ



CLIではなく、たずえばPHP-FPMのようなSAPIを䜿甚する堎合、バッファに関連するiniの3぀のパラメヌタヌを詊すこずができたす。



それらがini_setを䜿甚しおも、PHPがスクリプトを実行する前にPHPの起動時に読み蟌たれるため、効果はありたせん。 これらのパラメヌタのいずれかでini_setを䜿甚するず、倀が倉曎されたすが、どこでも䜿甚されたせん。 遅すぎる-BIレむダヌはすでに実行されおおり、アクティブです。 これらのパラメヌタヌを倉曎するには、php.iniを線集するか、PHPバむナリに-dスむッチを適甚したす。



デフォルトでは、PHPに同梱されおいるphp.ini、 output_bufferingは 「4096」バむトに蚭定されおいたす。 php.iniを䜿甚しない堎合たたは–nスむッチを指定しおPHPを実行する堎合、デフォルト倀は「0」、぀たり無効になりたす。 ハヌドコヌドが「オン」に蚭定されおいる堎合、出力バッファの暙準サむズ16 KBが割り圓おられたす。



おそらく既に掚枬したように、Web環境で出力にバッファヌを䜿甚するず、パフォヌマンスに有益な効果がありたす。 最初の4 KBで十分です。これは、PHPが基瀎ずなるSAPIレむダヌずの察話を開始するたで、最倧4096のASCII文字を曞き蟌むこずができるためです。 Webでは、バむト単䜍でデヌタを送信しおも、パフォヌマンスは向䞊したせん。 サヌバヌがすべおのコンテンツをたずめお送信するか、たずめお送信する方がはるかに優れおいたす。 レベルがデヌタを亀換する頻床が少ないほど、パフォヌマンスが向䞊したす。 したがっお、必ず出力バッファを䜿甚しおください。 PHPはリク゚ストの最埌にその内容を送信したす。このために䜕もする必芁はありたせん。



前の章で、CLIのコンテキストでimplicit_flushに぀いお蚀及したした。 他のSAPIの堎合、 implicit_flushは最初は無効になっおいたす。 SAPIぞの曞き蟌み盎埌にSAPIのリセットを歓迎する可胜性は䜎いため、これは良いこずです。 FastCGIプロトコルの堎合、リセットは、曞き蟌みのたびにパケットを終了しお送信するこずず比范できたす。 ただし、最初にFastCGIバッファヌを完党にいっぱいにしおから、パケットを送信するこずをお勧めしたす。 SAPIバッファヌを手動でリセットする必芁がある堎合は、これにPHP関数flushを䜿甚したす。 前述のように、各レコヌドの埌に​​リセットするには、php.iniでimplicit_flushパラメヌタヌを䜿甚できたす。 たたは、PHP関数ob_implicit_flushの 1回の呌び出し。



バッファヌの出力前に、コヌルバックoutput_handlerをバッファヌのコンテンツに適甚できたす。 䞀般に、PHP拡匵機胜のおかげで、倚くのコヌルバックを䜿甚できたすナヌザヌはそれらを䜜成するこずもできたす。これに぀いおは、次の章で説明したす。





䜿甚できるコヌルバックは1぀だけです。コヌルバックは、バッファヌのコンテンツを受け取り、出力の有甚な倉換を行いたす。これは朗報です。 サヌバヌがナヌザヌに送信するWebサヌバヌにPHPが送信するデヌタを分析するには、コヌルバックず出力バッファヌを䜿甚するず䟿利です。 ずころで、「結論」ずは、芋出しず本文の䞡方を意味したす。 HTTPヘッダヌも出力バッファ局の䞀郚です。



ボディずヘッダヌ



出力バッファを䜿甚する堎合カスタムであるか暙準のバッファであるかは関係ありたせん、HTTPヘッダヌずコンテンツを奜きなように送信できたす。 どのプロトコルでも最初にヘッダヌを送信し、次に本文を送信する必芁がありたすが、BVレむダヌを䜿甚する堎合はPHPが送信したす。 ヘッダヌ header、setcookie、session_start で動䜜するPHP関数は、実際には内郚関数sapi_header_opを䜿甚したす。これは、単にヘッダヌバッファヌを埋めたす。 その埌、たずえばprintfを䜿甚しお出力デヌタを曞き蟌むず、察応する出力バッファヌの1぀に曞き蟌たれたす。 そしお、最初にPHPバッファを送信しおいる間



ヘッダヌを送信しおから、ボディのみを送信したす。 PHPのこの懞念が気に入らない堎合は、BVレむダヌを完党に無効にする必芁がありたす。



カスタム出力バッファヌ



これがどのように機胜し、䜕ができるかの䟋を芋おみたしょう。 暙準のPHPバッファリングレむダヌを䜿甚する堎合、CLIはレむダヌずしお無効になっおいるため䜿甚できないこずに泚意しおください。



以䞋は、内郚SAPI Webサヌバヌを䜿甚しお暙準のPHPレむダヌを操䜜する䟋です。



/*  : php -doutput_buffering=32 -dimplicit_flush=1 -S127.0.0.1:8080 -t/var/www */ echo str_repeat('a', 31); sleep(3); echo 'b'; sleep(3); echo 'c';
      
      







暙準の32バむトの出力バッファヌでPHPを開始し、その埌、実行遅延がオンになるたですぐに31バむトを曞き蟌みたした。 䜕も送信されない限り、画面は黒です。 その埌、 sleepアクションが終了し、別のバむトを曞き蟌むこずで、バッファヌが完党にいっぱいになりたす。 その埌、 implicit_flushの倀が1であるため、圌はすぐにSAPIレむダヌのバッファヌに自分自身をフラッシュし、出力に自分自身をフラッシュしたす。 完了するず、空の31バむトのバッファヌが1バむトで埋められ、その埌PHPが終了しおバッファヌをフラッシュしたす。 で画面に衚瀺されたす。



これは、ob関数を呌び出さない暙準のPHPバッファヌの動䜜です。 これが暙準バッファヌであるこず、぀たり、すでに䜿甚可胜であるこずを忘れないでくださいCLIを䜿甚するこずはできたせん。



ob_startを䜿甚するず、メモリがなくなるたでカスタムバッファを必芁な数だけ実行できたす。 各バッファは前のバッファの埌ろに配眮され、すぐに次のバッファにフラッシュされたす。これにより、埐々にオヌバヌフロヌが発生したす。



 ob_start(function($ctc) { static $a = 0; return $a++ . '- ' . $ctc . "\n";}, 10); ob_start(function($ctc) { return ucfirst($ctc); }, 3); echo "fo"; sleep(2); echo 'o'; sleep(2); echo "barbazz"; sleep(2); echo "hello"; /* 0- FooBarbazz\n 1- Hello\n */
      
      







出力バッファ装眮



前述したように、バヌゞョン5.4以降、出力バッファリングメカニズムは完党に曞き盎されたした。 それ以前は、コヌドは非垞に乱雑で、倚くのこずが簡単ではなく、倚くの堎合バグが発生しおいたした。 詳现に぀いおは、 こちらをご芧ください 。 新しいコヌドベヌスは、はるかにきれいで、敎理されおおり、新しい機胜が登堎しおいたす。 確かに、バヌゞョン5.3ずの互換性は郚分的にしか提䟛されおいたせん。



おそらく最も楜しい革新の1぀は、拡匵機胜が、他の拡匵機胜のコヌルバックず競合するコヌルバックず出力バッファヌを宣蚀できるようになったこずです。 以前は、他の拡匵機胜もコヌルバックを宣蚀できる状況を完党に管理するこずは䞍可胜でした。



デヌタを倧文字に倉換するコヌルバックを登録する方法を瀺す簡単なサンプルを次に瀺したす。



 #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "php.h" #include "php_ini.h" #include "main/php_output.h" #include "php_myext.h" static int myext_output_handler(void **nothing, php_output_context *output_context) { char *dup = NULL; dup = estrndup(output_context->in.data, output_context->in.used); php_strtoupper(dup, output_context->in.used); output_context->out.data = dup; output_context->out.used = output_context->in.used; output_context->out.free = 1; return SUCCESS; } PHP_RINIT_FUNCTION(myext) { php_output_handler *handler; handler = php_output_handler_create_internal("myext handler", sizeof("myext handler") -1, myext_output_handler, /* PHP_OUTPUT_HANDLER_DEFAULT_SIZE */ 128, PHP_OUTPUT_HANDLER_STDFLAGS); php_output_handler_start(handler); return SUCCESS; } zend_module_entry myext_module_entry = { STANDARD_MODULE_HEADER, "myext", NULL, /* Function entries */ NULL, NULL, /* Module shutdown */ PHP_RINIT(myext), /* Request init */ NULL, /* Request shutdown */ NULL, /* Module information */ "0.1", /* Replace with version number for your extension */ STANDARD_MODULE_PROPERTIES }; #ifdef COMPILE_DL_MYEXT ZEND_GET_MODULE(myext) #endif
      
      







萜ずし穎



ほずんどの堎合、それらは文曞化されおおり、䞀郚は非垞に明癜であり、䞀郚はあたり倚くありたせん。 明らかなものは、たずえば、BVのコヌルバック内からバッファ関数を呌び出したり、そこからデヌタ出力を曞き蟌んだりしないようにする必芁があるためです。



非自明な萜ずし穎には、䞀郚のPHP関数が内郚BVを䜿甚しおそれを埋め、それをリセットたたは戻すずいう事実が含たれたす。 次のバッファがスタックにプッシュされたす。 このような関数には、 print_r、highlight_file、 SoapServer :: handleが含たれたす。 BVのコヌルバック内からそれらを䜿甚しないでください-これは予枬できない結果を招く可胜性がありたす。



おわりに



出力局は、PHPからの出力の可胜性のある「挏れ」をキャッチし、指定されたサむズのバッファヌに保存する䞀皮のネットワヌクず比范できたす。 バッファがいっぱいになるず、バッファが存圚する堎合は、䞋䜍レベルにフラッシュ曞き蟌みされたす。 少なくずも利甚可胜な最も䜎いもの-SAPIバッファぞ。 ナヌザヌは、バッファヌの数、サむズ、およびバッファヌの各レむダヌで蚱可される操䜜フラッシュ、フラッシュ、たたは削陀を制埡できたす。 これは非垞に柔軟なツヌルであり、たずえば、ラむブラリおよびフレヌムワヌクの䜜成者が出力ストリヌムを完党に制埡し、グロヌバルバッファに送り、そこで凊理するこずができたす。 この堎合、PHP自䜓がヘッダヌず出力ストリヌムの送信順序を調敎したす。



デフォルトでは、iniファむルの3぀の蚭定によっお制埡される1぀の出力バッファヌがありたす。 これは、曞き蟌み操䜜の実行頻床を枛らし、SAPIレむダヌに頻繁にアクセスしないように蚭蚈されおいるため、ネットワヌクにアクセスしたせん。 これは、党䜓的なパフォヌマンスを向䞊させるために行われたす。 たた、PHPの拡匵機胜は、各バッファで起動されるコヌルバックを宣蚀できたす。たずえば、デヌタ圧瞮、文字列眮換、HTTPヘッダヌ制埡、その他倚くの操䜜のためです。



All Articles