私はstackoverflowでこの質問を読んでいました:
https://stackoverflow.com/questions/104516/calling-php-functions-within-heredoc-strings
そして受け入れられた答えは、このような単純なPHPテンプレートを実行することです:
template.php:
<html> <head> <title> <?= $ title?> </ title> </ head> <body> <?= getContent()?> </ body> </ html>
index.php:
<?php $ title = 'デモタイトル'; function getContent(){ return '<p> Hello World!</p> '; } include(' template.php '); ?>
私にとって、上記は、template.phpが他のスクリプトで定義されている変数に依存しているという意味で、うまく構造化されていません。また、include('template.php')
を実行するときにinclude()を使用してコードを実行します(include()を使用して、すぐに実行されないクラスまたは関数を含めるのとは対照的です)。
テンプレートを関数内にラップする方が良いアプローチだと思います。
template.php:
<?php function template($ title、$ content){ ob_start(); ?> <html> <head> <title> <?= $ title?> </ title> </ head > <body> <?= $ content?> </ body> </ html> < ?php return ob_get_clean(); } ?>
index.php:
<?php require_once( 'template.php'); print template( 'Demo Title'、 '<p> Hello World!</ p > '); ?>
2番目のアプローチの方が優れていますか?それを行うためのさらに良い方法はありますか?
パラメータが指定されていないため、2番目のアプローチは行いません。
よく書かれた テンプレートシステムの動作の説明に関するエッセイ の動作はParrによるもので、テンプレートシステムやweb-mvcフレームワークを作成している人から引用されていることがよくあります。
個人的に、私が通常好むのは、プロパティ配列を使用してArrayObjectクラスを実装することであり、テンプレートは$this->propertyName
を参照します。これは、実際にはテンプレートオブジェクトの$this->property['name']
です。これは、__set
および__get
を使用するだけでも実現できるため、次のようになります。
class Template {
private $_scriptPath=TEMPLATE_PATH;//comes from config.php
public $properties;
public function setScriptPath($scriptPath){
$this->_scriptPath=$scriptPath;
}
public function __construct(){
$this->properties = array();
}
public function render($filename){
ob_start();
if(file_exists($this->_scriptPath.$filename)){
include($this->_scriptPath.$filename);
} else throw new TemplateNotFoundException();
return ob_get_clean();
}
public function __set($k, $v){
$this->properties[$k] = $v;
}
public function __get($k){
return $this->properties[$k];
}
}
テンプレートは次のようになります。
<html>
<head>
<title><?=$this->title?></title>
</head>
<body>Hey <?=$this->name?></body>
</html>
そしてそれを呼び出すことは次のようになります:
$view = new Template();
$view->title="Hello World app";
$view->properties['name'] = "Jude";
echo $view->render('hello.inc');
私が覚えている限り、これは古いSymfony 1.xとZend_Viewテンプレートエンジンがどのように見えるかであり、私にとっては問題ありません。
Codeigniterは私のお気に入りのフレームワークなので、Codeigniter風のソリューションを提案します。
class Template {
protected $path, $data;
public function __construct($path, $data = array()) {
$this->path = $path;
$this->data = $data;
}
public function render() {
if(file_exists($this->path)){
//Extracts vars to current view scope
extract($this->data);
//Starts output buffering
ob_start();
//Includes contents
include $this->path;
$buffer = ob_get_contents();
@ob_end_clean();
//Returns output buffer
return $buffer;
} else {
//Throws exception
}
}
}
テンプレートは次のようになります。
<html>
<head>
<title><?=$title?></title>
</head>
<body>
<?=$content?>
</body>
</html>
そして、クラスをインスタンス化し、配列のデータをコンストラクターパラメーターとして渡し、 'render'メソッドを呼び出すことによって、それをレンダリングします。
$data = array('title' => 'My title', 'content' => 'My content');
$tmpl = new Template('template.php', $data);
echo $tmpl->render();
このようにして、インクルードされたコードを直接実行するのではなく、テンプレートを読み取り可能に保つので、デザイナーは満足します。
最初 template.php
は、そのままdreamweaver/bluegriffon/whateverにロードして、サーバー側の知識のないWebデザイナーが編集する方が簡単です。編集プロセス中に壊れる可能性があります。
私は最初にそれを利点のあるHTMLのように見せるために行きます、サードパーティのデザイナーが通常好む方法。
テンプレートは常に外部変数に依存し、PHPは動的言語であるため、コンパイル時にそれらが存在することを強制する方法はありません。したがって、最初のアプローチはおそらく問題ありませんが、まだいくつかの問題があります。
非常に簡単なアプローチは、できれば非常に短い名前で、これらの両方を処理する関数を書くことです。それを_()
と呼ぶことは一般的な慣習のようです。単純なバージョンは次のようになります。
_function _($raw) {
if (isset($raw)) {
return htmlspecialchars($raw);
}
}
_
そして、あなたのテンプレートでは、次のようにします:
_<title><?= _($title) ?></title>
_
_()
関数を使用して行うその他のこと:
htmlspecialchars
呼び出しをオーバーライドできるように、2番目の引数を指定します。Array
とObject
ではなく、意味のあるもの(または空の文字列)を生成しないようにします。