(ドット連結)より速いまとめはじめにPHPに関する話題の中では、PHPコードをどのように書けば最適化されるのかに関するtipsがブログなどでもたびたび話題に出てきています。このようなtipsが本当に有効なのか、どうして有効なのか解説している記事は少なく、その信憑性は気になるとこです。63+をもとに、いくつか抜粋して検証していきます。PHPソースコードの入手やはり、内部の動きを知るにはソースコードを読むのが一番です。本稿でもソースコードをもとに解説を行います。http://jp.php.net/downloads.phpこちらから最新版のソースコードが入手できます。現在の最新バージョンは5.2.6になります。本稿ではPHP5.2.6をベースに解説していきます。echoのほうがprintより速いまずはじめに検証を行うのは、“⁠echoのほうがprintより速い⁠”というtipsです。echo、printはご存知のとおり文字列を出力します。それでは実際に下記のコードを用いてベンチマークをとってみます。用意したコードは1000回ループを回して、echoとprintを実行した合計時間で評価を行うシンプルなコードです。それぞれのコードは5行目でechoを使っているか、printを使っているかの違いがあります。benchmark_print.phpfloat(0.000159978866577)わずかではありますが、echoのほうが速い結果になりました。それでは、この違いはどこからくるものなのでしょうか。実際にコードを追ってみましょう。printの実体はZend/zend_compile.c内のzend_do_print()にあります。zend_do_print()ではresultに返り値を必要としており、result変数に返り値が設定されています。opline->result;}echoの実体はZend/zend_compile.c内のzend_do_echo()にあります。zend_do_echo()ではzend_do_print()とは違い、返り値を必要としていないことがわかります。SET_UNUSED(opline->op2);}結果を返さない分、echoのほうが早くなります。printを使いわけたほうがよさそうです。@によるエラー制御は遅いPHPではエラー制御演算子として@を使用することができます。PHPの式の前に付けることで、その式で発生したエラーメッセージを無視することができます。新たにprintに@を付けたコードを用意し、先ほどと同様に実行してみます。benchmark_use_atmark.phpfloat(0.000759124755859)@を付けたほうが遅くなりました。遅い原因を探ってみましょう。}“@⁠”が付いた構文に関する処理はZend/zend_language_parser.yで定義されており、zend_do_begin_silence()とzend_do_end_silence()構文が実行される前と後に実行されています。次にzend_do_begin_silence()とzend_do_end_silence()について調べます。どちらの関数もZend/zend_compile.cで定義されてます。SET_UNUSED(opline->op2);}zend_do_begin_silenceとzend_do_end_silenceで設定されたopcodeとop_typeからhandlerが選ばれ、Zend/zend_vm_execute.h内のexecuteで選択されたhandlerが実行されます。zend_vm_decode[op-.op_type]];その結果、zend_do_begin_silence()ではZEND_BEGIN_SILENCE_SPEC_HANDLERが、zend_do_end_silence()ではZEND_END_SILENCE_SPEC_TMP_HANDLERが呼ばれます。次にZEND_BEGIN_SILENCE_SPEC_HANDLERとZEND_END_SILENCE_SPEC_TMP_HANDLERについて見ていきます。この関数もZend/zend_vm_execute.hに定義されています。ZEND_VM_NEXT_OPCODE();}二つのhandler間でzend_alter_ini_entry_ex()が呼ばれ、“⁠error_reporting⁠”を0に設定してエラー表示をoffにし、構文の実行後に“⁠error_reporting⁠”の値をもとに戻してます。単純にerrorを出力する関数にフラグを渡してエラー出力の抑制を行っているのではなく、このようにhandlerを二つ挟んでいるために遅くなっていることがわかります。(ドット連結)より速いこちらのtipsについても、はじめに簡単なコードを用いてベンチマークをとってみます。使用するのは'a'、'b'、'c'の3文字を出力するコードです。benchmark_dot.phpfloat(0.000324964523315)実行してみると、ドット連結のほうがわずかですが遅い結果になりました。これについてもコードを追ってみます。;カンマ区切りでは、カンマごとに分解していき、その都度zend_do_echoに渡しているのがわかります。}ドット連結の場合は、文字通りですが一度文字の連結を行ってからechoされています。定数と定数の連結の場合には下記の関数が呼ばれます。concat_function()関数で連結が行われています。'c'と順にechoされますが、ドットの場合、定数の連結ではZEND_CONCAT_SPEC_CONST_CONST_HANDLERを呼ばなければならないため、一度すべての文字を連結するためにこのhandlerを呼ぶオーバヘッドが生じると考えられます。まとめPHP最適化tipsについて検証を行いました。あれが速いこれが遅いと言ってきましたが、決してこう書かなければいけないというわけでもありません。コードの読みやすさやメンテナンスのしやすさも同時に重要だと思います。可読性やコードスタイルを考慮してこれらのtipsの導入を考えてください。PHPの内部実装について触れるいい機会になると思うのでぜひご活用ください。次回も引き続き検証を進めるとともに、検証に役立つgdbを用いたPHP内部の動きを追う方法についても紹介したいと思います。Ltd.ページ内容の全部あるいは一部を無断で利用することを禁止します⁠。個別にライセンスが設定されている記事等はそのライセンスに従います。