PHPのechoとob_startと自前バッファ出力の速度比較
PHPでWebサイトを作る場合、テンプレートとなる基本のHTMLを用意しておき、その中のコンテンツだけ動的に生成して出力する、いわゆるCMS(Contents Management System)的な作り方をすることも多いと思います。
…フレームワーク使ってる人は知りませんよ?
ぼくPHPのフレームワークって苦手なんです。仕事で仕方なく使うケースもなくもなくもないですが、出来ることなら避けたい。だってそもそもPHP自体がフレームワークじゃないですか。言語自体がテンプレートエンジンとなっているのに、なにゆえその上に重たいクラスだのなんだのを載せたがるのか。理解に苦しみます。
…と、そんなぼくの主義主張はともかく、元となる静的なテンプレート用HTMLを読み込み、動的に生成されたコンテンツを結合する際、文字列でアレコレやる方法もあればob_startで出力バッファを溜め込んでアレコレやる方法もあると思うんです。
今回はその速度を比較してみよう、というお話。
ざっくりとしたテンプレート例
前置きではわかりづらかった気もするので、ざっくりとした例を挙げておきます。
■template.php
<html>
<body>
<h1>テンプレートだよーん</h1>
<ul class="menu">
<li>メニュー1</li>
<li>メニュー2</li>
<li>メニュー3</li>
</ul>
<div class="content">
<?php echo $content; ?>
</div>
</body>
</html>
■content1.php
<?php
$content = "コンテンツ1だよーん\n";
require_once 'template.php';
?>
■content2.php
<?php
ob_start();
echo "コンテンツ2だよーん\n";
$content = ob_get_contents();
require_once 'template.php';
?>
解説
template.phpでは全ページ共通のメニューを配置しています。
content1.phpとcontent2.phpはそれぞれのコンテンツをセットしてからtemplate.phpを呼び出す動作。
一口にテンプレートを用意してコンテンツと結合させる、といってもいくつかの方法があり、中でも自前でバッファを作るパターン(content1のパターン)とob_startに任せるパターン(content2のパターン)は比較的メジャーなんじゃないかなーと思います。
なんとなーく経験的に前者のほうが早そうと思って使っていますが、実際に計測したことはなかったので今回それを計測していきます。
ob_startとechoの速度計測
■基本となるコード
$start_time = microtime(true);
genHtml();
echo microtime(true) - $start_time.' sec.';
テスト環境はWindows10上で動作するnginx+PHP7.4.7です。
echoのみで出力した場合
PHPコード
function genHtml()
{
echo '<html><body><textarea>';
for ($i = 0; $i < 10000; $i++) {
echo "テストテストテストテストテスト\n";
}
echo '</textarea></body></html>';
}
"テストテストテストテストテスト"という文字列を1万行出力するだけのコードです。
結果
0.0067369937896729 sec.
ob_startでバッファしてから出力した場合
PHPコード
function genHtml()
{
ob_start();
echo '<html><body><textarea>';
for ($i = 0; $i < 10000; $i++) {
echo "テストテストテストテストテスト\n";
}
echo '</textarea></body></html>';
$html = ob_get_contents();
ob_end_clean();
echo $html;
}
結果
0.0049200057983398 sec.
当然ですが、逐一echoするよりもかなり早い。
自前でバッファリングしてから出力した場合
PHPコード
function genHtml()
{
$html = '<html><body><textarea>';
for ($i = 0; $i < 10000; $i++) {
$html .= "テストテストテストテストテスト\n";
}
$html .= '</textarea></body></html>';
echo $html;
}
結果
0.0043032169342041 sec.
ob_startよりもはやーい!
【オマケ】バッファを配列にした場合
PHPコード
function genHtml()
{
$htmlArray = array();
$htmlArray[] = '';
echo implode('', $htmlArray);
}
結果
0.0050148963928223 sec.
おぅふ…。ob_startより遅い。
まとめ
テンプレートエンジンがどうたらこうたらと前置きしましたが、要するにechoとob_startと自前バッファの速度比較でした。
■結果
逐次echo | 0.0067369937896729 sec. |
---|---|
ob_start | 0.0049200057983398 sec. |
自前バッファ | 0.0043032169342041 sec. |
自前バッファ(配列) | 0.0050148963928223 sec. |
ということで、ob_startにバッファリングを任せるよりも自前で変数を用意してバッファリングしたほうが早い、という結果になりました。ある意味当たり前ですかね?
でもでも、そうじゃないかなー?と思っていても実際に試すまでは安心して使用できないので試してみて良かったと思っています。
尚、自前バッファを配列にしたパターンですが、これは過去に文字列操作が苦手な言語で痛い目にあったことがあるためです。具体的に名前を挙げてしまうとVisual Basicって言うんですけどね…。文字列に文字列を加算するたびに何やら裏で操作をしているようでどんどんパフォーマンスが低下していくの。
それに比べると配列に蓄えたほうが圧倒的に早かったので、VB使っていた頃はバッファ変数にはもっぱら配列を使用していました。だいぶ古い頃のVBですし、今は問題ないと思いますが、PHPではどうかなー?と思って試したんですね。
文字列に文字列をどんどん追加するだけの操作でもPHPは余計なことをしていないようで十分な速度が出て一安心。
今後も自前でバッファを作って、テンプレートとコンテンツを合体させるCMSを作ろうと思いました。
以上、何かの参考になれば幸いです。