プレーンなPHPを使用してテンプレートシステムを構築する方法は?


15

私はstackoverflowでこの質問を読んでいた:

/programming/104516/calling-php-functions-within-heredoc-strings

そして受け入れられた答えは、このような単純なPHPテンプレートを実行するように言っています:

template.php:

<html>
    <head>
        <title> <?= $ title?> </ title>
    </ head>
    <本体>
        <?= getContent()?>
    </ body>
</ html>

index.php:

<?php

$ title = 'デモタイトル';

関数getContent(){
    return '<p> Hello World!</ p>';
}

include( 'template.php');

?>

私には、template.phpが他のスクリプトで定義された変数に依存するという意味で、上記の構造はうまくありません。また、実行時にコードを実行するためにinclude()をinclude('template.php')使用しています(include()を使用して、すぐには実行されないクラスまたは関数を含めるのとは対照的です)。

テンプレートを関数内にラップするのがより良いアプローチだと思います:

template.php:

<?php

関数template($ title、$ content){
    ob_start(); ?>

<html>
    <head>
        <title> <?= $ title?> </ title>
    </ head>
    <本体>
        <?= $ content?>
    </ body>
</ html>

    <?php return ob_get_clean();
}

?>

index.php:

<?php

require_once( 'template.php');

print template( 'Demo Title'、 '<p> Hello World!</ p>');

?>

2番目のアプローチはより良いですか?それを行うためのさらに良い方法はありますか?

回答:


12

パラメーターに名前が付けられていないため、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テンプレートエンジンの外観であり、私にとっては問題ありません。


TinyButStrongも同様のことを行います
-Izkata

いくつかのスコアのループをどのように処理しますか?別の「サブ」テンプレートを使用しますか?
ライアン

テンプレートで$ thisを使用するのをやめる方法はないのでしょうか。たとえば、$ titleや$ nameだけです。
ライアン

1
@Ryan extract($this->properties);includeステートメントの直前に、プロパティを変数に抽出するために使用できます。
ジョイスバブ

1

テンプレートは常に外部変数に依存し、PHPが動的言語であるため、コンパイル時にそれらが存在することを強制する方法はありません。したがって、最初のアプローチはおそらく大丈夫です。ただし、まだいくつかの問題があります。

  • この例では、出力のHTMLエンコードを考慮していません。つまり、潜在的なXSS脆弱性が存在します。
  • これらの変数のいずれかが設定されていない場合、コードは警告を発します。警告が意味をなすかどうかはわかりません(変数はオプションである可能性があります)。

非常に簡単なアプローチは、これらの両方を処理する関数を、できれば非常に短い名前で書くことです。それを呼び出すこと_()は一般的な慣習のようです。単純なバージョンは次のようになります。

function _($raw) {
    if (isset($raw)) {
        return htmlspecialchars($raw);
    }
}

次に、テンプレートで次のようにします。

<title><?= _($title) ?></title>

この_()関数で行うべき他のこと:

  • htmlspecialchars生の文字列ではなくHTMLを渡したい場合のために、呼び出しをオーバーライドできるように2番目の引数を与えます。
  • 型チェックを追加して、配列とオブジェクトがandを生成せArrayObject、むしろ意味のある(または空の文字列)を生成するようにします。
  • 国際化サポートを追加します(さらに別の引数)。
  • デバッグモードの場合、変数の名前が定義されていない場合は、特別な書式で変数の名前を出力します。これにより、テンプレートに何か問題があるかどうかを一目で確認できます。

1

最初の方法template.phpそのままでdreamweaver / bluegriffon / whateverにロードし、サーバー側の知識のないWebデザイナーが編集します。2番目の方法は...まだ可能ですが、編集プロセス中に壊れる可能性が高くなります。 。

サードパーティのデザイナーが通常好む方法で、利点のあるHTMLのように見せるために最初に行きます


どのような意味で?ドラッグアンドドロップでは変更できないということですか?テキストでは、2番目は最初のものと同じですが、PHPの2、3行がラップされています。そのため、常にその構造を持つと仮定すると、手で編集するのは難しくありません。
ライアン

1
優れたテンプレートは開発者にとって意味があり、優れたテンプレートはデザイナーにとって意味があります。
Citricguy

1

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();

この方法では、含まれているコードを直接実行することはなく、テンプレートを読みやすくすることもできるため、デザイナーは満足するでしょう。


-3

PHPはプログラミング言語ではありません。したがって、言語に実際の型システムがない場合は、厳密に型指定された文字を書くことはできません。ただし、PHP-StormのようなIDEを使用して、必要なトリックを実行できます。

あなたのビュー定義:

interface mySimpleView { 
  public function getTitle(); 
} 

テンプレートファイル:

<?php
/**
* @var $this mySimpleView  <== Your IDE will try to use this type.
*/
?>

<h1><?= $this->getTitle() ?></h1>
<p><?= $this->getContent() ?></p> <!-- <= IDE will warn you !  -->

Iこの回答のように(明確に「PHPはプログラミング言語ではありませんが、」常に争いになるだろうが。
ロニー
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.