PHPテンプレートベンチマーク ---- PHPTALに注目
PHPTALのチュートリアル
http://phptal.org/manual/en/split/firstexample.html
を、
のそれぞれで書いてみて、ベンチマークを取ってみました。(ただし、テーブルに流し込むデータが空ならTABLEをPタグとテキストに置き換え、テーブルの行には行番号を追加した)
PHPTALのXHTML出力は、文字列中のタグ文字を勝手にエスケープするので、SmartyとネイティブPHPのコードにはそれぞれ、escape:'html'とhtmlspecialcharsをつけています。でないと公平じゃないし。
ベンチマークといっても、単純に100回連続で同じリクエストを送信した結果を、特徴の違う2つのマシンで計測してみただけですが。
Windows Vista / Core2 Duo E8300 2.83GHz / Apache2.2.9 / PHP5.2.6
Processing HTML 100 times : total time 2.0660 sec (48.403 query/sec 20.66 msec/query) Processing PHP(native) 100 times : total time 2.0900 sec (47.847 query/sec 20.90 msec/query) Processing Smarty 100 times : total time 2.7180 sec (36.792 query/sec 27.18 msec/query) Processing PHPTAL 100 times : total time 2.9620 sec (33.761 query/sec 29.62 msec/query)
Ubuntu-8.04 Serever / Celeron 2.40GHz / Apache2.2.8 / PHP5.2.4
Processing HTML 100 times : total time 1.0484 sec (95.383 query/sec 10.48 msec/query) Processing PHP(native) 100 times : total time 0.9738 sec (102.693 query/sec 9.74 msec/query) Processing Smarty 100 times : total time 2.3589 sec (42.393 query/sec 23.59 msec/query) Processing PHPTAL 100 times : total time 2.5022 sec (39.964 query/sec 25.02 msec/query)
PHPTALとSmartyの計測結果は誤差程度です。PHPTALのほうがやや早い場合もありました。
Smartyが遅くて使い物にならないと思い込んでいたけど、最近はそうでもないんですね。遅いと思い込んでいたのは何年前の話やら…。PHP5がまだマイナーで、普通のCPUがPentium3だったころの印象から、完全にPHPテンプレートエンジンを避けていました。しまった、 http://d.hatena.ne.jp/tanakahisateru/20080924/1222190229 でSmartyをけなしすぎました。Smartyごめんよ。
CPUに瞬発力があるなら、場合によってはSmartyを使ってもいいかもしれないけど、SmartyはやっぱりPHPタグの別の書き方でしかない(PHPタグと同じ場所に別の構文で同じ意味のことを書く)ので、やっぱり速度面のデメリットがあるんなら、まだPHPそのものをテンプレート言語にするのが有利にはたらく場合のほうが多い気がしました。
ただし、書き換えに対して表示が圧倒的に多いサイトの場合、データベース接続のオーバーヘッドを避けるため、テンプレートエンジンのページキャッシュ機能を利用するのは有効かもしれません。まあ、それとて自力で制御するという手がないわけではないけど…。
それより、PHPTALとSmartyとの性能差がほとんどないということが驚きでした。「PHPとそれほど違わないのに少し重いSmarty」よりも、「同じように少し重くなるだけで、作りに画期的な変化をもたらしてくれるPHPTAL」は、注目に値しますね。
PHPTALのなにが画期的?
PHPTALには
- タグ構造を維持したまま、属性に制御コードを書く(デザイナフレンドリ)
- 元ページのDOMノードをラップするマクロを定義できる
という嬉しい特徴があります。
デザイナがHTMLだけ書き、プログラマがそこにコードを注入した場合、PHPやSmartyだとHTMLとしての見た目が変わってしまうけど、拡張属性にコードを書くテンプレートなら、コード注入後でも見た目が変わりません。つまり、Tapestry/Kid/Genshiと同じやり方でいけるということ。
「DOMノードをラップするマクロ」ってなんのこと?ってのは要するに、
<?php include "layout/block_begin.inc"; ?> <p>hoge</p> <?php include "layout/block_end.inc"; ?>
みたいなのを
<div metal:use-macro="layout.html/block"> <p metal:fill-slot="contents">hoge</p> </div>
と書けるということ。2つの.incファイル(<div>とそれに対応する</div>が別々になってしまう)が、単一のマクロファイルに収まります(ひとつの外部ファイルには、複数のマクロを置いとける)。Kid/Genshiのpy:matchには及ばないけど、Dreamweaverのテンプレートと編集可能領域よりは強力。
参考
100回リクエストベンチに使ったRubyスクリプト
require 'net/http' TIMES = 100 def execprofile(name) print "Processing #{name}\n" start = Time::now for i in 1 .. TIMES {|| yield } total = Time::now - start printf("%d times : total time %.4f sec (%.3f query/sec %.2f msec/query)\n\n", TIMES, total.to_f, TIMES / total.to_f, 1000.0 * total.to_f / TIMES ) end HOST = 'localhost' BASEURI = '/path/to/your/test/' #テスト対象のURI execprofile('HTML') {|| Net::HTTP.get(HOST, BASEURI+'page_html.htm') } execprofile('PHP(native)'){|| Net::HTTP.get(HOST, BASEURI+'page_php.php') } execprofile('Smarty') {|| Net::HTTP.get(HOST, BASEURI+'page_smarty.php') } execprofile('PHPTAL') {|| Net::HTTP.get(HOST, BASEURI+'page_tal.php') }