文字列定数、いわゆる文字列リテラルとしてPHPソースコード内にデータを埋め込んでおく場合と、スクリプト実行中に外部のファイルからデータを取り込むのとではどちらが速いのか知りたいところです。
ウェブ開発において、ページデザインと処理部分を分割する場合など外部のテンプレートファイルを取り込んで必要なデータを置換して表示させたりしますが、このときテンプレートをソースコード内に埋め込んでいた方が有利なのかどうか検証したいと思います。
そこで以下のようなソースコードを書いてみました。以前書いたbench()関数を使って処理にかかった時間を採取していきます。
まぁハードディスクがよほどポンコツならまた違った結果になるやも知れませんが・・・。
PCのスペックはコチラ で行いました。
■ソースコード(which.php)
bench(1);
include('./singleq.php'); // includeした時にシングルクォート文字列がパース(解釈)される
$singleq= singleq(); // singleq()関数の返り値を受け取る
echo bench(),"(singleq)<br />\n";
bench(1);
include('./doubleq.php'); // ダブルクォート文字列が解釈される
$doubleq= doubleq(); // doubleq()関数の返り値を受け取る
echo bench(),"(doubleq)<br />\n";
bench(1);
include('./fileget.php');
$fileget= fileget(); // fileget()関数の返り値を受け取る
echo bench(),"(fileget)<br />\n";
bench(1);
include('./whileget.php');
$whileget= whileget(); // whileget()関数の返り値を受け取る
echo bench(),"(whileget)<br />\n";
function bench($reset="")
{
global $micro,$time;
(!isset($time) or !empty($reset)) and list($micro, $time)= explode(' ', microtime());
list($m, $t)= explode(' ', microtime());
return $m-$micro+$t-$time;
}
?>
■ソースコード(singleq.php)
// 3bytesをシングルクォートの文字列で返す例
function singleq()
{
return 'aaa';
}
?>
■ソースコード(doubleq.php)
// 3bytesをダブルクォート文字列で返す例
function doubleq()
{
return "aaa";
}
?>
■ソースコード(fileget.php)
// 3bytesデータの入ったファイルdata.txtを読み出して返す
function fileget()
{
return file_get_contents("./data.txt");
}
?>
■ソースコード(whileget.php)
// 3bytesデータの入ったファイルdata.txtを、fgets()で一行ずつ連結していったものを返す
function whileget()
{
$fp= fopen("./data.txt", "rb");
$data= '';
while (!feof($fp)) $data.= fgets($fp);
fclose($fp);
return $data;
}
?>
以上、ソースコード例では冗長にならないように扱うデータを3バイトで書きましたが、まずはデータを5KBにして実行してみます。
[5KBデータで3回実行結果]
0.00037908554077148(doubleq)
0.00049090385437012(fileget)
0.00059390068054199(whileget)
0.00039100646972656(singleq)
0.00028896331787109(doubleq)
0.00037288665771484(fileget)
0.00044798851013184(whileget)
0.00049090385437012(singleq)
0.00037789344787598(doubleq)
0.0004880428314209(fileget)
0.0005950927734375(whileget)
なぜかシングルクォートがダブルクォートよりも時間かかっています。
ということで確認のためsingleq()とdoubleq()の順番を入れ替えてみます。
[single<=>double]
0.00037789344787598(singleq)
0.00048303604125977(fileget)
0.00058794021606445(whileget)
0.00039410591125488(doubleq)
0.0003659725189209(singleq)
0.00047802925109863(fileget)
0.00058698654174805(whileget)
0.0003960132598877(doubleq)
0.0003669261932373(singleq)
0.00048494338989258(fileget)
0.00058794021606445(whileget)
今度はダブルクォートの方が少し遅くなりました。とは言っても、誤差の範囲内でしょうかね。。
これは最初の関数実行でなにか初期の負荷がかかっているのでしょうか?
試しに最初にダミーの関数(文字列リテラルを変数に代入したりfile_get_contents()関数やfopen()関数で開いてデータを読み出したり一通り行う)を追加して計測してみます。
[dummy()追加]
0.00045609474182129(singleq)
0.00065493583679199(fileget)
0.00067901611328125(whileget)
0.00050997734069824(doubleq)
0.00037097930908203(singleq)
0.00047802925109863(fileget)
0.00058507919311523(whileget)
0.00037002563476562(doubleq)
0.00036001205444336(singleq)
0.00046896934509277(fileget)
0.00058102607727051(whileget)
大して変わらない感じですね。。
[順番を戻して]
0.00036096572875977(doubleq)
0.00053501129150391(fileget)
0.00059199333190918(whileget)
0.00045490264892578(singleq)
0.00045609474182129(doubleq)
0.00065398216247559(fileget)
0.0006721019744873(whileget)
0.0003659725189209(singleq)
0.00037002563476562(doubleq)
0.00046992301940918(fileget)
0.0005791187286377(whileget)
いずれもほとんど差はないと見ていいかと思います。
では次にデータ量を10倍の50KBに増やして計測してみます。
[50KBデータで3回実行結果]
0.0011940002441406(doubleq)
0.00083208084106445(fileget)
0.0018959045410156(whileget)
0.0010230541229248(singleq)
0.0010819435119629(doubleq)
0.00058102607727051(fileget)
0.0017690658569336(whileget)
0.0010659694671631(singleq)
0.0010910034179688(doubleq)
0.00058603286743164(fileget)
0.0017681121826172(whileget)
はい、少しだけですがはっきりと差がついてきました。
このレベルではシングルクォートとダブルクォートでは大差ないと言っていいでしょう。
変数展開のない文字列リテラルでもダブルクォートで囲って書いて気にしなくてよさそうですね。
テンプレート読み出しはスクリプト実行中にfile_get_contents()関数を使うことで有利にできそうです。