「Smarty は速い」は都市伝説
Smarty が広まった理由のひとつに、動作が速いというのがある。Smarty はテンプレートをコンパイルして PHP ファイルに変換し、それを実行する。そのため、実行速度が速いと信じられている。
しかし、これは大きな誤解である。PHP ファイルを include() する方法と比べ、Smarty は約 2〜3 倍遅い。なぜなら、Smarty のテンプレートをコンパイルしてできる PHP ファイルがクソだから。つまり、いくら PHP ファイルに変換するからといっても、遅いコードに変換されるんだから、人間が書いたふつうの PHP ファイルのほうがよっぽど速いというわけ。
たとえば次のようなコードがあるとする。
<table> {section loop=$list name=item} <tr bgcolor="{cycle values='#FFCCCC,#CCCCFF'}"> <td>{$list[item]|escape}</td> </tr> {/section} </table>
これをコンパイルすると、こんなクソみたいな PHP コードが生成される。
<?php /* Smarty version 2.6.18, created on 2008-01-01 00:00:00 compiled from template3.tpl */ ?> <?php require_once(SMARTY_CORE_DIR . 'core.load_plugins.php'); smarty_core_load_plugins(array('plugins' => array(array('modifier', 'escape', 'template3.tpl', 1, false),array('function', 'cycle', 'template3.tpl', 4, false),)), $this); ?> <h1><?php echo ((is_array($_tmp=$this->_tpl_vars['title'])) ? $this->_run_mod_handler('escape', true, $_tmp) : smarty_modifier_escape($_tmp)); ?> </h1> <table> <?php unset($this->_sections['item']); $this->_sections['item']['loop'] = is_array($_loop=$this->_tpl_vars['list']) ? count($_loop) : max(0, (int)$_loop); unset($_loop); $this->_sections['item']['name'] = 'item'; $this->_sections['item']['show'] = true; $this->_sections['item']['max'] = $this->_sections['item']['loop']; $this->_sections['item']['step'] = 1; $this->_sections['item']['start'] = $this->_sections['item']['step'] > 0 ? 0 : $this->_sections['item']['loop']-1; if ($this->_sections['item']['show']) { $this->_sections['item']['total'] = $this->_sections['item']['loop']; if ($this->_sections['item']['total'] == 0) $this->_sections['item']['show'] = false; } else $this->_sections['item']['total'] = 0; if ($this->_sections['item']['show']): for ($this->_sections['item']['index'] = $this->_sections['item']['start'], $this->_sections['item']['iteration'] = 1; $this->_sections['item']['iteration'] <= $this->_sections['item']['total']; $this->_sections['item']['index'] += $this->_sections['item']['step'], $this->_sections['item']['iteration']++): $this->_sections['item']['rownum'] = $this->_sections['item']['iteration']; $this->_sections['item']['index_prev'] = $this->_sections['item']['index'] - $this->_sections['item']['step']; $this->_sections['item']['index_next'] = $this->_sections['item']['index'] + $this->_sections['item']['step']; $this->_sections['item']['first'] = ($this->_sections['item']['iteration'] == 1); $this->_sections['item']['last'] = ($this->_sections['item']['iteration'] == $this->_sections['item']['total']); ?> <tr bgcolor="<?php echo smarty_function_cycle(array('values' => '#FFCCCC,#CCCCFF'), $this);?> "> <td><?php echo ((is_array($_tmp=$this->_tpl_vars['list'][$this->_sections['item']['index']])) ? $this->_run_mod_handler('escape', true, $_tmp) : smarty_modifier_escape($_tmp)); ?> </td> </tr> <?php endfor; endif; ?> </table>
ぱっと見た限りでは、次のようなことがわかる。
- テンプレートにおける変数への参照が、コンパイル後の PHP コードではネストした配列の要素へのアクセスとなっている。
- ループするごとに、使ってもいない各種ループカウンタを設定している。
- escape のような modifier を呼び出すときは、いちいち is_array() で配列かどうか調べている。
こんなことしてたら、いくら PHP コードにコンパイルしても遅いに決まっている。どう考えても、普通の PHP ファイルを include() するほうが速いし、なにより簡単。
このように、「Smarty が速い」なんていうのは誤った認識である。スピードを理由に Smarty を選ぶのはやめたほうがよい。
以上、Smarty 撲滅委員会からのお知らせでした。