テンプレート
全体として、テンプレート エンジンは「良いもの」です
PHP/Perl プログラマーとして、多くのテンプレート エンジン (fastTemplate、Smarty、Perl の HTML::Template) だけでなく、私自身のテンプレート エンジン (bTemplate[1] (著者) )、何度も言いました。
しかし、同僚との長い議論の結果、多くのテンプレート エンジン (私自身が作成したものを含む) が単に間違っていると確信するようになりました。 唯一の例外は Smarty[2] だと思いますが、この記事の残りの部分を考慮すると、あまりにもかさばりすぎてまったく無意味だと思います。ただし、Smarty (または同様のソリューション) を選択する必要がある理由はいくつかあります。これについては、この記事で後ほど説明します。
この記事では、テンプレートの理論について説明します。ほとんどの「テンプレート エンジン」が太すぎる理由を確認し、最終的には軽量、小型、高速な代替エンジンを検討します。
ダウンロードとライセンス
この記事で使用されているテンプレート クラスとすべての例は、ここからダウンロードできます: template.zip [3]。これらのファイルのコードは、OSI [5] の下でリリースされた MIT オープンソース ライセンス [4] に基づいて使用できます。
テンプレート エンジンに関する背景知識
まず、テンプレート エンジンに関する背景知識を勉強しましょう。テンプレート エンジンは、ビジネス ロジック (データベースからのデータの取得や貿易コストの計算など) をデータの表示から分離するように設計されています。テンプレート エンジンは、次の 2 つの主要な問題を解決します:
この分離を実現する方法
「複雑な」PHP コードを HTML から分離する方法
これにより、理論的には、PHP の経験のない HTML デザイナーでも、PHP コードを見ずにこれを行うことができます 条件に応じて、サイト。
ただし、テンプレート システムには多少の複雑さも伴います。まず、複数のファイルから派生した「ページ」ができました。通常、ビジネス ロジックを担当するメインの PHP ページ、サイト全体の全体的なレイアウトをレンダリングする外側の「レイアウト」テンプレート、内側のコンテンツ固有のテンプレート、データベース抽象化レイヤー、およびテンプレート エンジン自体 (これらは複数のファイルで構成されている場合もあれば、構成されていない場合もあります)。また、すべての PHP ページの最初と最後に単に「ヘッド」ファイルと「フッター」ファイルを含める人もいる可能性があります。
これにより 1 ページに対して生成されるファイルの数はかなりになります。ただし、PHP パーサーは非常に高速であるため、サイトのトラフィックが大量でない限り、使用されるファイルの数はそれほど重要ではない可能性があります。
ただし、テンプレート システムでは別のレベルの処理が導入されることに注意してください。テンプレート ファイルはインクルードするだけでなく、解析する必要もあります (テンプレート システムに応じて、正規表現、文字列置換、コンパイル、字句解析など、さまざまな方法でこれを実行できます)。これが、テンプレートの速度テストが人気になっている理由です。テンプレート エンジンはさまざまな方法を使用してデータを解析するため、一部のエンジンは他のエンジンよりも高速です (また、一部のテンプレート エンジンは他のエンジンよりも豊富な機能を提供します)。
テンプレート エンジンの基本
簡単に言えば、テンプレート エンジンは C で書かれたスクリプト言語 (PHP) を利用します。これらの埋め込みスクリプト言語内には、別の疑似スクリプト言語 (テンプレート エンジンがサポートするタグは何でも) があります。単純な変数のオーバーライドとループを提供するものもあります。条件付きループやネストされたループを提供するものもあります。他のもの (少なくとも Smarty) は、バッファ層だけでなく、PHP の比較的大きなサブセットへのインターフェイスを提供します。
Smarty が正しい方向に最も近いと思うのはなぜですか?なぜなら、Smarty の目標は「PHP コードと HTML コードを分離する」ことではなく、「ビジネス ロジックをパフォーマンスから分離する」ことだからです。これは大きな違いのように思えないかもしれませんが、まさに重要な点です。テンプレート エンジンの最終的な目標は、HTML からすべてのロジックを削除することではありません。プレゼンテーション ロジックをビジネス ロジックから分離する必要があります。
データを正しく表示するためのロジックだけが必要な例はたくさんあります。たとえば、ビジネス ロジックはデータベースからユーザーのリストを取得することです。パフォーマンス ロジックでは、ユーザー リストを 3 列で表示する場合があります。おそらく、ユーザー リスト関数を変更して 3 つの配列を返すようにするのは愚かな考えかもしれません。結局のところ、関数はデータを次にどうするかについて気にすべきではありません。ただし、テンプレート ファイルにはいくつかのロジックが欠落しており、それがまさにあなたがやりたいことです。
Smarty はこれについては正しい (PHP の多くの機能を利用できるようにする) が、まだ多くの問題があります。基本的には、新しい構文を使用して PHP へのインターフェイスを提供するだけです。そこから始めると、あまりスマートには見えません。実際には < foreach --args ?> よりも {foreach --args} を書くほうが簡単ではないでしょうか?これが簡単だと思う場合は、巨大なテンプレート ライブラリを含める場合に、この分離の本当の意味を理解するのが簡単かどうかを自問してください。確かに、Smarty は他にも多くの優れた機能を提供しますが、これらの利点は、Smarty クラス ライブラリを含める負担なしで得られるようです。
別の解決策
私が主に提唱している解決策の 1 つは、PHP コードをネイティブ スクリプト言語として使用する「テンプレート エンジン」です。これは以前にも行われたことは知っています。最初に見たときは、「なぜこんなことをするの?」と思いましたが、同僚の議論を考慮した後、最終的な目的を分離したときに、PHP コードを使用してコードを直接実装しました。テンプレート システム (コメントを除いて、コードはわずか 25 行しかかかりません) を使用して、その利点を実感しました。
このシステムにより、私たちのような開発者は、出力の書式設定に使用できるコアの PHP 関数にアクセスできるようになります。日付の書式設定などのタスクはテンプレートで処理する必要があります。さらに、テンプレートは通常の PHP ファイルであるため、Zend Performance Suite [6] や PHP Accelerator [7] のようなバイトコード キャッシュ プログラムはテンプレートを自動的にキャッシュできます (したがって、アクセスするたびにテンプレートを更新する必要はありません)。 。これは、プログラムが PHP ファイルとして認識できるような名前をテンプレート ファイルに付けることを忘れない限り、大きな利点です (通常は、ファイルに .php 接尾辞が付いていることを確認するだけで済みます)。
このアプローチは従来のテンプレート エンジンよりもはるかに優れていると思いますが、議論すべき問題がいくつかあることは確かです。最も明白な反論は、PHP コードは複雑すぎるため、設計者に PHP の学習を強制すべきではないというものです。実際、PHP コードの構文は、Smarty のような高度なテンプレート エンジンの構文と比べて (単純ではないにしても) ほぼ同じくらい単純です。さらに、設計者は =$var;?> のような PHP 略語を使用できます。これは {$var} よりもはるかに複雑ですか?もちろん、少し時間はかかりますが、慣れてしまえば、テンプレート ファイルを解析する手間をかけずに PHP のパワーを活用できるようになります。
2 番目に、そしておそらくより重要なことですが、PHP ベースのテンプレートには本質的なセキュリティがありません。 Smarty には、テンプレート ファイル内の PHP コードを完全に無効にするオプションが用意されています。これにより、開発者はテンプレートがアクセスできる関数と変数を制限できます。悪意のあるデザイナーがいない場合、これは問題にはなりません。ただし、外部ユーザーにテンプレートのアップロードまたは変更を許可すると、ここで示した PHP ベースのソリューションにはまったくセキュリティがありません。任意のコードをテンプレートに入力して実行できます。はい、print_r($GLOBALS) も可能です (これにより、悪意のあるユーザーがスクリプト内の任意の変数にアクセスできるようになります)。
ただし、私が個人的にまたは仕事で書いたプロジェクトのほとんどは、エンドユーザーがテンプレートを変更したりアップロードしたりすることを許可していません。そうであれば、問題は存在しません。それでは、コードを見てみましょう。
例
これは、単純なユーザーリストページの例です。
require_once('template.php');
/**
* この変数は、すべてのテンプレート ファイルへのファイル システム パスを保持します。
*/
$path = './templates/'
$tpl = & 新しいテンプレート($path);
$tpl->set('タイトル', 'ユーザーリスト');
$body = & 新しいテンプレート($path); $body->set('user_list', fetch_user_list());
/**
* 外側のテンプレートのテンプレート オブジェクトを作成し、その変数を設定します。
*/
$tpl->set('body', $body->fetch('user_list.tpl. php'));
/**
* 内部テンプレートのテンプレート オブジェクトを作成し、その変数を設定します。
* fetch_user_list() 関数は単にユーザーの配列を返します。
*/
echo $tpl->fetch('index.tpl.php');
?> 注目すべき重要な概念が 2 つあります。 1 つ目は、内部テンプレートと外部テンプレートの概念です。外部テンプレートには、サイトの主な外観と操作性を定義する HTML コードが含まれています。内部テンプレートには、サイトのコンテンツ領域を定義する HTML コードが含まれています。もちろん、任意の数のレイヤーに任意の数のテンプレートを含めることができます。通常、リージョンごとに異なるテンプレート オブジェクトを使用するため、名前空間の問題は発生しません。たとえば、競合を心配することなく、内部テンプレートと外部テンプレートの両方に「title」という変数を含めることができます。
これは、ユーザーのリストを表示するために使用されるテンプレートの簡単な例です。特殊な foreach と endforeach の構文については、PHP マニュアル [8] で説明されていることに注意してください。それは完全にオプションです。
また、なぜテンプレート ファイルの名前に .php 接尾辞を付けるのか疑問に思われるかもしれません。あはは、多くの PHP バイトコード キャッシュ ソリューション (phpAccelerator など) では、PHP ファイルとして認識されるためには、ファイルに .php 接尾辞が必要です。これらのテンプレートは PHP ファイルなので、これらの利点を活用してみてはいかがでしょうか?