332 Views
September 17, 13
スライド概要
(PHPカンファレンス2013での講演内容です) 突然ですが…そのPHPの定石は正しいと言えるでしょうか?「echoの方がprintより速い」「エラー抑制演算子@は常に避けるべき」などなど、PHPを書く上で"定石"と呼ばれるコーディングスタイルがいくつもあります。それらの挙動をパフォーマンス計測とPHPの内部実装に踏み込みつつ、わかりやすく検証していきます。
2023年10月からSpeaker Deckに移行しました。最新情報はこちらをご覧ください。 https://speakerdeck.com/lycorptech_jp
PHPコアから読み解く 定石の嘘ホント ヤフー株式会社 蒋(蒋池) 東龍
レジュメ • 前編(5分) – もろもろ始める前に • 中編(24分) – エラー制御演算子 – 比較演算子 – 標準出力 • 後編(1分) – おわり 2
もろもろ始める前に PHP における定石を 何か知っていますか? 3
もろもろ始める前に その定石は どのようにして 正しいと判断しましたか? 4
もろもろ始める前に 定石とは何でしょうか? 5
もろもろ始める前に デジタル大辞泉 より 6
もろもろ始める前に 物事をするときの、 最上とされる方法・手順 7
もろもろ始める前に つまり PHP の定石とは 8
もろもろ始める前に PHP でコーディングする時の 最上とされる方法・手順 9
もろもろ始める前に 定石の良し悪しは どうやって判断すれば よいのでしょうか? 10
もろもろ始める前に 数字 および 論理から 判断する必要がある 11
もろもろ始める前に 数字に関しては…… 12
もろもろ始める前に 実行時の 速度を計測する 13
もろもろ始める前に コンパイルやネットワークを 計測しないようにするため 任意のコードを microtime() で挟む (単位は usec) 14
もろもろ始める前に
<?php
$start = microtime(true);
$max = <計測回数>;
for($i = 0; $i < $max; $i++)
{
<該当処理>
}
$end = microtime(true);
$tm = $end - $start;
error_log("time[$tm]usec¥n");
//?>
15
もろもろ始める前に 論理に関しては…… 16
もろもろ始める前に スクリプトの オペコードを解析する 17
もろもろ始める前に 最小の命令単位である オペコードについて考えるため vld(Vulcan Logic Disassembler) でダンプする 18
もろもろ始める前に <番号> <オペコード> <オペランド1> ※オペコード=オペレーター=最小単位の処理 ※オペランド=引数 ※対応するハンドラは ZEND_*_HANDLER() 19 <オペランド2>
もろもろ始める前に 答え(を覚えること)は 全く重要ではありません 20
もろもろ始める前に どっちの方が速いのか どうしてそうなのか 考えてみることが重要! 21
もろもろ始める前に ここからは クイズ形式です 22
もろもろ始める前に 一人では寂しいので 双方向で進めさせてください! 23
もろもろ始める前に 1問につき8分! 24 1. 出題(50秒) 2. 黙考(10秒) 3. 質問、挙手、指名(1分) 4. 回答(3分) 5. 考察(3分)
エラー制御演算子 エラー制御演算子 なし vs あり どっちが速い? (100回計測) 25
エラー制御演算子 26 for($i = 0; $i < $max; $i++) { include('nothing.php'); } for($i = 0; $i < $max; $i++) { @include('nothing.php'); } ※nothing.phpは存在しない ※nothing.phpは存在しない
エラー制御演算子 あれこれ 27
エラー制御演算子 速 い 0.088059902191162 usec 28 0.085351943969727 usec
エラー制御演算子 11 INCLUDE_OR_EVAL INCLUDE 29 'nothing.php', 11 BEGIN_SILENCE 12 INCLUDE_OR_EVAL INCLUDE 'nothing.php', 13 END_SILENCE ~7
エラー制御演算子 エラー制御演算子は一時的に error_reporting を 0 にしている エラーがあった時には 出力が減るので処理は速くなる 30
比較演算子 比較演算子 ($a == $b) vs ($a === $b) どっちが速い? (10万回計測) 31
比較演算子 32 $a = "1"; $a = "1"; for($i = 0; $i < $max; $i++) { if(1 == $a){ // } } for($i = 0; $i < $max; $i++) { if(1 === $a){ // } }
比較演算子 あれこれ 33
比較演算子 速 い 0.017616987228394 usec 34 0.0085439682006836 usec
比較演算子 !2 = $a 11 IS_EQUAL 35 !2 = $a 1, !2 11 IS_IDENTICAL 1, !2
比較演算子 オペランドの型が違う時 == の場合には型変換を試みるが === の場合には型変換を試みない 型が違う場合には === の方がずっと速い 36
標準出力 標準出力 print() vs echo() どっちが速い? (1000回計測) 37
標準出力 for($i = 0; $i < $max; $i++) { print("abcdefghijklmn opqrstuvwxyz¥n"); } ※実際には1行 38 for($i = 0; $i < $max; $i++) { echo("abcdefghijklmn opqrstuvwxyz¥n"); } ※実際には1行
標準出力 あれこれ 39
標準出力 0.00041317939758301 usec 0.00037407875061035 usec 速 い 40
標準出力 10 PRINT 'abcdefghijklmn opqrstuvwxyz%0A’ (~6に結果) 10 ECHO 'abcdefghijklmn opqrstuvwxyz%0A’ ※実際には1行 ※実際には1行 11 FREE 41 ~6
標準出力 異なるオペコードだが PRINT は ECHO を ラッピングしていて戻り値もある (必ず 1 が返る) echo() を利用した方がよい 42
おわり 定石は 前提条件によって 全く姿を変えてしまう 43
おわり だから 44
おわり 定石は 使えることよりも 考えることの方が大切 45
おわり さらには 46
おわり ただ暗記するよりも 考えてみた方が 楽しいし覚えられる 47
おわり • オペコード – http://blog.golemon.com/ • PHP コード最適化 Best Practices 63 – http://d.hatena.ne.jp/koto2/20080518/12 11070116 48
おわり ありがとうございました 49