TwigやDjangoと同様に、Twangoには下記のような特徴がある。
ではTwangoに無い機能はというと、コンテンツキャッシュ(テンプレートから変換したPHPのキャッシュだけでなく、DB等から取得したデータを埋め込んだHTMLのキャッシュ)機能が無い。それはテンプレートエンジンがやらなくてもいいと思うから。コンテンツキャッシュは、Apacheのmod_cacheなり、PEAR::Cache_Liteなり、P2_Cacheなりを使えばいいと思う。
Twangoの具体的な使い方についてはこのページの中ほどからの例を参考に。なるべくTwigに似せるようにしたけど面倒だったので微妙に違うところもある
<?php
/**
* Twango
* @see http://0-oo.net/sbox/php-tool-box/template-like-twig
* @copyright 2010 dgbadmin@gmail.com
* @license http://0-oo.net/pryn/MIT_license.txt (The MIT license)
*/
function twango($path, $tplValues = array(), $cacheDir = '.') {
$cachePath = "$cacheDir/" . str_replace('/', '._', $path) . '.cache.php';
//テンプレート更新チェック
if (!file_exists($cachePath) || filemtime($cachePath) < filemtime($path)) {
//変数出力のPHP化(フィルターあり)
$callback = '$tokens = explode("|", trim($matches[1]));';
$callback .= '$s = "$" . array_shift($tokens);';
$callback .= 'foreach ($tokens as $token) $s = "$token($s)";';
$callback .= 'return "<?php echo htmlSpecialChars($s, ENT_QUOTES) ?>";';
$fn = create_function('$matches', $callback);
$tpl = preg_replace_callback('/\{\{(.+)\}\}/U', $fn, file_get_contents($path));
//継承のPHP化
$regexp = '/\{% extends [\'"](.+)[\'"] %\}(.*)$/s';
$extends = '<?php$2' . __FUNCTION__ . '("$1", $tplValues, $cacheDir);';
$blockStart = 'if (!function_exists("block_$1")) {';
$blockStart .= 'function block_$1($tplValues) { extract($tplValues) ?>';
$blockEnd = '<?php }}';
if (preg_match($regexp, $tpl)) { //継承の場合
$tpl = preg_replace($regexp, $extends, $tpl);
} else {
$blockStart = '<?php ' . $blockStart;
$blockEnd .= '; block_$1($tplValues) ?>';
}
//その他のPHP化
$forNum = '<?php foreach (range($2, $3) as $$1) { ?>';
$forKV = '<?php foreach ($$3 as $$1 => $$2) { ?>';
$ptn = array(
'/\{% block (\w+) %\}/' => $blockStart,
'/\{% endblock (\w+) %\}/' => $blockEnd,
'/\{% for (\w+) in (\d+)\\.\\.(\d+) %\}/U' => $forNum,
'/\{% for (\w+), ?(\w+) in (\w+) %\}/U' => $forKV,
'/\{% for (\w+) in (\w+) %\}/U' => '<?php foreach ($$2 as $$1) { ?>',
'/\{% if (.+) %\}/U' => '<?php if ($1) { ?>',
'/\{% else *if (.+) %\}/U' => '<?php } else if ($1) { ?>',
'/\{% else %\}/' => '<?php } else { ?>',
'/\{% end.*%\}/' => '<?php } ?>',
'/\{%(.+)%\}/sU' => '<?php$1?>',
'/\{#.+#\}/sU' => '',
);
$tpl = preg_replace(array_keys($ptn), array_values($ptn), $tpl);
file_put_contents($cachePath, trim($tpl), LOCK_EX);
}
extract($tplValues);
require($cachePath);
}
<?php
require('twango.php');
$values = array(
'title' => 'タイトル',
'msg' => '<こんにちは twango!> ',
'kbn' => 1,
'arr' => array('foo', 'bar'),
);
twango('tmpl.html', $values);
tmpl.html
<html>
<head>
<!-- 変数の値を出力 -->
<title>{{ title }}</title>
</head>
<body>
<!-- 変数にフィルターをかけて出力 -->
{{ msg|trim|strToUpper }}
<hr>
<!-- コメント -->
{# 表示されない #}
<hr>
<!-- 配列のループ -->
{% for str in arr %}
{{ str }},
{% endfor %}
<hr>
<!-- ループでKEYとVALUEの両方を取り出す -->
{% for key, value in arr %}
{{ key }} => {{ value }},
{% endfor %}
<hr>
<!-- 始まりと終わりの数を指定してループ -->
{% for i in 1..3 %}
{{ i }},
{% endfor %}
<hr>
<!-- if文の条件部分はPHPそのままで -->
{% if $kbn == 1 %}
1
{% elseif $kbn == 2 %}
2
{% else if $kbn == 3 %}
3
{% else %}
4
{% endif %}
<hr>
<!-- 普通のPHP文を埋め込める -->
{% var_dump($values) %}
<hr>
<!-- 複数の行でもOK -->
{%
echo '今は';
$now = date('Y-m-d H:i:s');
%}
{{ now }}ですよ
<hr>
<!-- ブロックごとに継承できる -->
{% block test %}
ここは継承
{% block test2 %}
継承の入れ子
{% endblock test2 %}
継承終わり
{% endblock test %}
<hr>
<!-- 1行のブロックもOK -->
{% block 1_line %}1行のブロック{% endblock 1_line %}
</body>
</html>
tmpl.html.cache.php
<html>
<head>
<!-- 変数の値を出力 -->
<title><?php echo htmlSpecialChars($title, ENT_QUOTES) ?></title>
</head>
<body>
<!-- 変数にフィルターをかけて出力 -->
<?php echo htmlSpecialChars(strToUpper(trim($msg)), ENT_QUOTES) ?>
<hr>
<!-- コメント -->
<hr>
<!-- 配列のループ -->
<?php foreach ($arr as $str) { ?>
<?php echo htmlSpecialChars($str, ENT_QUOTES) ?>,
<?php } ?>
<hr>
<!-- ループでKEYとVALUEの両方を取り出す -->
<?php foreach ($arr as $key => $value) { ?>
<?php echo htmlSpecialChars($key, ENT_QUOTES) ?> => <?php echo htmlSpecialChars($value, ENT_QUOTES) ?>,
<?php } ?>
<hr>
<!-- 始まりと終わりの数を指定してループ -->
<?php foreach (range(1, 3) as $i) { ?>
<?php echo htmlSpecialChars($i, ENT_QUOTES) ?>,
<?php } ?>
<hr>
<!-- if文の条件部分はPHPそのままで -->
<?php if ($kbn == 1) { ?>
1
<?php } else if ($kbn == 2) { ?>
2
<?php } else if ($kbn == 3) { ?>
3
<?php } else { ?>
4
<?php } ?>
<hr>
<!-- 普通のPHP文を埋め込める -->
<?php var_dump($values) ?>
<hr>
<!-- 複数の行でもOK -->
<?php
echo '今は';
$now = date('Y-m-d H:i:s');
?>
<?php echo htmlSpecialChars($now, ENT_QUOTES) ?>ですよ
<hr>
<!-- ブロックごとに継承できる -->
<?php if (!function_exists("block_test")) {function block_test($tplValues) { extract($tplValues) ?>
ここは継承
<?php if (!function_exists("block_test2")) {function block_test2($tplValues) { extract($tplValues) ?>
継承の入れ子
<?php }}; block_test2($tplValues) ?>
継承終わり
<?php }}; block_test($tplValues) ?>
<hr>
<!-- 1行のブロックもOK -->
<?php if (!function_exists("block_1_line")) {function block_1_line($tplValues) { extract($tplValues) ?>1行のブロック<?php }}; block_1_line($tplValues) ?>
</body>
</html>
<html>
<head>
<!-- 変数の値を出力 -->
<title>タイトル</title>
</head>
<body>
<!-- 変数にフィルターをかけて出力 -->
<こんにちは TWANGO!>
<hr>
<!-- コメント -->
<hr>
<!-- 配列のループ -->
foo,
bar,
<hr>
<!-- ループでKEYとVALUEの両方を取り出す -->
0 => foo,
1 => bar,
<hr>
<!-- 始まりと終わりの数を指定してループ -->
1,
2,
3,
<hr>
<!-- if文の条件部分はPHPそのままで -->
1
<hr>
<!-- 普通のPHP文を埋め込める -->
NULL
<hr>
<!-- 複数の行でもOK -->
今は2010-08-27 15:32:33ですよ
<hr>
<!-- ブロックごとに継承できる -->
ここは継承
継承の入れ子
継承終わり
<hr>
<!-- 1行のブロックもOK -->
1行のブロック
</body>
</html>
<?php
require('twango.php');
$values = array(
'title' => '継承',
'msg' => '継承だよ',
'kbn' => 2,
'arr' => array('foo' => 123, 'bar' => 456),
);
twango('extends.html', $values);
extends.html
{% extends "tmpl.html" %}
{% block test2 %}
<div>{{ arr['foo'] }}</div>
{% endblock test2 %}
{% block 1_line %} 1行ブロックも継承 {% endblock 1_line %}
extends.html.cache.php
<?php
if (!function_exists("block_test2")) {function block_test2($tplValues) { extract($tplValues) ?>
<div><?php echo htmlSpecialChars($arr['foo'], ENT_QUOTES) ?></div>
<?php }}
if (!function_exists("block_1_line")) {function block_1_line($tplValues) { extract($tplValues) ?> 1行ブロックも継承 <?php }}
twango("tmpl.html", $tplValues, $cacheDir);
<html>
<head>
<!-- 変数の値を出力 -->
<title>継承</title>
</head>
<body>
<!-- 変数にフィルターをかけて出力 -->
継承だよ
<hr>
<!-- コメント -->
<hr>
<!-- 配列のループ -->
123,
456,
<hr>
<!-- ループでKEYとVALUEの両方を取り出す -->
foo => 123,
bar => 456,
<hr>
<!-- 始まりと終わりの数を指定してループ -->
1,
2,
3,
<hr>
<!-- if文の条件部分はPHPそのままで -->
2
<hr>
<!-- 普通のPHP文を埋め込める -->
NULL
<hr>
<!-- 複数の行でもOK -->
今は2010-08-27 15:34:02ですよ
<hr>
<!-- ブロックごとに継承できる -->
ここは継承
<div>123</div>
継承終わり
<hr>
<!-- 1行のブロックもOK -->
1行ブロックも継承
</body>
</html>
Smartyは最近仕事で初めて使った。便利だと思わないので、自分から使おうとは思わない。
DjangoはGoogle App Engine SDKでHello World程度に使ったことがある。
Twigは使ったことがない。というかインストールしたことがない。
Rubyなら、というかRailsならERBを使う。そりゃそうか。
普段自分が使ってるテンプレートエンジンは、PHPです。