日別アーカイブ: 2014年5月18日

PHPテンプレートエンジンを使おう Twig編

PHPテンプレートエンジンについて解説・紹介していく企画、素のPHPSmarty2.xSmarty3.xと紹介してきて、満を持してのTwig登場である。

PHPテンプレートエンジンTwigとは

そもそも、Twigとは何なのだろうか。疑問を解決するためにお手元の検索エンジンで検索しても、小枝の画像ばっかり出てくる(笑)。Twigとは、フランスのSensioLabsというソフトウェア会社にスポンサードされている、オープンソースのWEBアプリケーションフレームワークSymfonyを構成する標準バンドルパッケージの一つである(Symfony公式サイトTwig公式サイト)。
WEBアプリケーションフレームワークという言葉が出てきたが、WEBアプリケーションを作るための”概して便利な”枠組みのことで、Symfonyは企業サイトやらAPIやらのWEB上に展開するサービスを作成する際に、ヴァージョンの管理やライブラリの管理、データ構造など様々なことを、MVCの考え方に基づいて整理・管理してくれる仕組みだ。
MVCにのっとっているため、Symfonyは多人数が関わるプロジェクトなどにおいて強みを発揮する。逆に言うと、小規模で作ったら作りっぱなしのようなプロジェクトに導入する意義はそれほど無い。でもそうした小規模プロジェクトでも、Symfonyの特定機能だけ利用したいという需要があるかもしれないので、Symfonyでは機能の多くをモジュール化しており、Symfony本体を導入しなくてもかいつまんで使えるようになっている。そのモジュールの一つが、PHPテンプレートエンジンのTwigというわけだ。

Twigの利用方法

Twig単体で利用する場合、先程紹介したTwig公式サイトより本体を落としてきて、libディレクトリ内のTwigディレクトリを適当な場所に配置する。あとはキャッシュ用のディレクトリと、テンプレートファイル格納用のディレクトリを必要に応じて作っておけばよい。なおインストールにはcomposerというSymfonyのモジュールを使う方法もあり、ファイルの依存関係を管理するというcomposer自体の機能も使いたい場合には、一緒に導入しておいても良いだろう。
で、ひとまずcomposerを使用しないインストールが済んだとして、呼び出し側のPHPスクリプトではこういった感じに書く。Smarty2.xの説明で出した例と同じことをやっているので、適宜比較などしてほしい。

//index.php
 
require_once("Twig/Autoloader.php");
Twig_Autoloader::register();
$loader = new Twig_Loader_Filesystem("twigtmp/");
$twig = new Twig_Environment($loader, array("cache" => "cache/", "debug" => false));
$template = $twig->loadTemplate("default.html.twig");
$template->display(array("title" => "トップページ"));

まず、先程のTwigディレクトリにあるAutoloader.phpを読み込む。これは関連ファイルを全て読み込むためのクラスで、Twig_Autoloader::registerメソッドを呼ぶ。
次に$loaderに入れているのはテンプレートをロードするクラスのインスタンスで、Twig_Loader_Filesystemの場合コンストラクタにテンプレートファイルのあるディレクトリへのパスを引数として与える。ファイルを読み込むのでなくインラインのStringでテンプレートを用意する場合はTwig_Loader_Stringクラスなど、いくつか種類があるのだが、とりあえずTwig_Loader_Filesystemだけ覚えておけば良い。

次のTwig_Environmentというクラスのインスタンス作成時に、$loaderと配列にした各種設定を渡している。”cache”はキャッシュを入れるディレクトリへのパス、”debug”はデバッグの有無など。キャッシュを使わずデバッグモードもオフならば、第一引数のみで良い。

$templateはTwig_environmentのメソッドであるLoadTemplate()で読み込むテンプレートファイル名を与える。そして$templateのdisplay()メソッドの引数に、変数の値をラベル付き配列で与える。これで標準出力へと出力されることになる。
テンプレート側の記述はこのように。変数の先頭に$をつけず、二重波括弧({{}})で変数名を囲む。

//default.html.twigの記述
 
<!doctype html>
<html lang="ja">
<head>
<title>{{ title }} | サンプル株式会社</title>
</head>
<body>
.
.
</body>
</html>

商品一覧ページをTwigで作ってみる

それでは、Smarty3.xを用いて作った商品一覧ページを、Twigで作り直してみよう。まずはテンプレートファイル側。

 
<!-- base.html.twig -->
<!doctype html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="css/base.css" type="text/css">
{% if description is not empty %}
<meta name="description" content="{{ description }}">
{% else %}
<meta name="description" content="サンプル株式会社のホームページです">
{% endif %}
{% if keywords is not empty %}
<meta name="keywords" content="{{ keywords }}">
{% else %}
<meta name="keywords" content="サンプル株式会社,小売業,日本">
{% endif %}
<title>{{ title }} | サンプル株式会社</title>
{% block head %}
{% endblock head %}
</head>
<body>
<div id="wrapper">
<header>
<h1>サンプル株式会社</h1>
</header>
<div id="main">
{% block main %}
<article>
<h1>デフォルト文章</h1>
<p>mainのブロックに指定が無い場合のデフォルト文章です。</p>
.
.
</article>
{% endblock main %}
</div>
<footer>
<p>サンプル株式会社 2012-{{ "now"|date("Y") }} all rights reserved.</p>
</footer>
</div>
</body>
</html>
 
<!-- item.html.twig -->
<li>
<section>
<h1>{{ value.name }}</h1>
<p>{{ value.description }}</p>
<p>{{ value.price|number_format(0) }}円</p>
<p><a href="http://xxxxxxxx.xxx/item.php?id={{ value.id }}" title="{{ value.name }}の商品詳細">>>商品詳細へ</a></p>
</section>
</li>
 
<!-- itemlist.html.twig -->
{% extends "base.html.twig" %}
{% block main %}
<article>
<h1>サンプル株式会社の商品一覧</h1>
{% if items is empty %}
<p>現在取り扱っている商品はありません</p>
{% else %}
<p>当社が取り扱う商品の一覧です。</p>
<ul id="itemlist">
{% for value in items %}
{% include "item.html.twig" %}
{% endfor %}
</ul>
{% endif %}
</article>
{% endblock main %}

テンプレートファイル側でのSmartyとの違いは、プレースホルダの書き方は先程説明の通り。ifなどの制御構造は括弧だけでなく、end〜という閉じタグになるところや、foreachの書き方がfor inになるところ、blockのname=でなく直接block名指定になるところ、比較演算子がis notのような自然言語的な書き方になることなど、細かい違いが結構あると言える。配列のラベルへのアクセスは同じだが、Twigの場合value[“name”]のようなアクセスも可能。そして、オブジェクトのメンバへのアクセスも同じ書き方で出来る。
修飾子が”|”の後に続くのも同じ。あとは、オシャレなマニュアルでチェックしてほしい。

呼び出し側はこのように。

//itemlist.php
 
require_once("Twig/Autoloader.php");
Twig_Autoloader::register();
$loader = new Twig_Loader_Filesystem("twigtmp/");
$twig = new Twig_Environment($loader, array("cache" => "cache/", "debug" => false));
$items = array();
 
//例の如く、下記の配列が帰ってきたと仮定
 
$items = array(
array("id" => "1","name" =>"商品A","description" => "さわやかなミントの香りの牛車です(牛は食べられません)","price" => "100000"),
array("id" => "2","name" =>"商品B","description" => "官位です。これがあれば思いのまま(返品不可)","price" => "3000"),
array("id" => "10","name" =>"商品C","description" => "古今和歌集です。新版が出たので在庫一掃セールです","price" => "16000")
);
$page = array(
"description" => "サンプル株式会社の商品一覧ページです。",
"keywords" => "サンプル株式会社,ネットショップ",
"title" => "当社商品の一覧",
"items" => $items
);
$template = $twig->loadTemplate("itemlist.html.twig");
$template->display($page);

まあ既に説明した内容である。displayメソッドに持たせる引数が標準で配列であるため、テンプレート側からそのままラベルのみでアクセスしていることに注意。
あと、この例だとキャッシュを有効化しているので、いじってテストなどする際には、結果確認の前にキャッシュディレクトリの中身を廃棄しておこう(これをわざわざやらなくて良いためにデバッグモードがあるらしい。先程知った)。

SmartyとTwigはどちらが良いのか

以上、Twigについても見てきた。仕組みはそれほどSmartyと変わらないので、乗り換えは楽だろう。ただ、乗り換え後過去資産を活用しようとすると変換は面倒臭いので、そこはあまり期待しない方が良い。
良く言われるSmarty3.xとTwigの速度面の差だが、確かに体感などTwigの方がキビキビ動いている印象がある(Smarty2.xには劣るけど)。速度比較については厳密度は分からないけれど、こんなデータもある。
あとはマニュアルのオシャレさなんかを基準にどちらを使うか決めれば良いだろう。