16

グループプロジェクトの場合、言語の経験が少ない人が HTML で {name} などのタグを使用できるように、PHP 用のテンプレートエンジンを作成しようとしています。PHP はそのタグを配列から事前定義された変数に置き換えます。ループをサポートするだけでなく。

これはプロジェクトの予想をはるかに超えていますが、私は PHP の経験があるので、忙しくしておくのは良い挑戦になると思いました!

私の主な質問は、パーサーのループ部分をどのように行うか、そしてこれがそのようなシステムを実装するための最良の方法であるかということです。既存のテンプレート システムを推奨する前に、経験のために自分で作成することをお勧めします。これは、プロジェクトのすべてが独自のものでなければならないためです。

現時点では、正規表現と preg_replace_callback を使用して基本的な解析が行われ、$data[name] が存在するかどうかがチェックされ、存在する場合は置き換えられます。

さまざまな方法でループを実行しようとしましたが、正しい軌道に乗っているかどうかわかりません!

解析エンジンに与えられたデータの例は次のとおりです。

Array
(
    [title] => The Title
    [subtitle] => Subtitle
    [footer] => Foot
    [people] => Array
        (
            [0] => Array
                (
                    [name] => Steve
                    [surname] => Johnson
                )

            [1] => Array
                (
                    [name] => James
                    [surname] => Johnson
                )

            [2] => Array
                (
                    [name] => josh
                    [surname] => Smith
                )

        )

    [page] => Home
)

そして、解析していたページは次のようなものでした:

<html>
<title>{title}</title>
<body>
<h1>{subtitle}</h1>
{LOOP:people}
<b>{name}</b> {surname}<br />
{ENDLOOP:people}
<br /><br />
<i>{footer}</i>
</body>
</html>

次のようなものが生成されます。

<html>
<title>The Title</title>
<body>
<h1>Subtitle</h1>
<b>Steve</b> Johnson<br />
<b>James</b> Johnson<br />
<b>Josh</b> Smith<br />
<br /><br />
<i>Foot</i>
</body>
</html>

あなたの時間はこれで信じられないほど高く評価されています!

どうもありがとう、

Ps私は、経験のためにすでに存在するものに似たものを作成しようとしているため、適切にフォーマットされた理解しやすい質問が反対票を投じられることに完全に同意しません。

Pps このトピックについては非常に多くの意見が飛び交っているようです。反対票を投じないでください。彼らはあなたとは異なる意見を持っているからです。誰もが自分の権利を持っています!

4

6 に答える 6

22

簡単な方法は、テンプレートを PHP に変換して実行することです。

$template = preg_replace('~\{(\w+)\}~', '<?php $this->showVariable(\'$1\'); ?>', $template);
$template = preg_replace('~\{LOOP:(\w+)\}~', '<?php foreach ($this->data[\'$1\'] as $ELEMENT): $this->wrap($ELEMENT); ?>', $template);
$template = preg_replace('~\{ENDLOOP:(\w+)\}~', '<?php $this->unwrap(); endforeach; ?>', $template);

たとえば、これはテンプレート タグを埋め込み PHP タグに変換します。

$this->showVariable()$this->data$this->wrap()およびを参照したことがわかります$this->unwrap()。それが私が実装しようとしているものです。

showVariable関数は変数の内容を表示します。wrapそしてunwrap、クロージャーを提供するために各反復で呼び出されます。

これが私の実装です:

class TemplateEngine {
    function showVariable($name) {
        if (isset($this->data[$name])) {
            echo $this->data[$name];
        } else {
            echo '{' . $name . '}';
        }
    }
    function wrap($element) {
        $this->stack[] = $this->data;
        foreach ($element as $k => $v) {
            $this->data[$k] = $v;
        }
    }
    function unwrap() {
        $this->data = array_pop($this->stack);
    }
    function run() {
        ob_start ();
        eval (func_get_arg(0));
        return ob_get_clean();
    }
    function process($template, $data) {
        $this->data = $data;
        $this->stack = array();
        $template = str_replace('<', '<?php echo \'<\'; ?>', $template);
        $template = preg_replace('~\{(\w+)\}~', '<?php $this->showVariable(\'$1\'); ?>', $template);
        $template = preg_replace('~\{LOOP:(\w+)\}~', '<?php foreach ($this->data[\'$1\'] as $ELEMENT): $this->wrap($ELEMENT); ?>', $template);
        $template = preg_replace('~\{ENDLOOP:(\w+)\}~', '<?php $this->unwrap(); endforeach; ?>', $template);
        $template = '?>' . $template;
        return $this->run($template);
    }
}

wrap()and関数ではunwrap()、スタックを使用して変数の現在の状態を追跡します。正確にwrap($ELEMENT)は、現在のデータをスタックに保存し、内部の変数$ELEMENTを現在のデータに追加unwrap()し、スタックからデータを復元します。

セキュリティを強化するために、次のビットを追加して<、PHP エコーに置き換えました。

$template = str_replace('<', '<?php echo \'<\'; ?>', $template);

基本的に、<?<%、または<script language="php">.

使用法は次のようなものです。

$engine = new TemplateEngine();
echo $engine->process($template, $data);

これは最善の方法ではありませんが、実行できる方法の 1 つです。

于 2011-02-16T15:34:22.397 に答える
6

まず、PHP IS A TEMPLATE PARSERについて説明します。

あなたがしていることは、テンプレート パーサーからテンプレート パーサーを作成するようなものであり、無意味であり、率直に言って、smarty などのテンプレート パーサーが無意味なタスクでうまく機能していることを繰り返します。

あなたがすべきことは、冗長なパーサーではなくテンプレートヘルパーを作成することです。プログラミング用語では、テンプレートファイルはビューと呼ばれ、特定の名前が付けられた理由の1つは、人々がモデルとは別にそこにあることを知っているからです。 、ドメインロジックなど

あなたがしなければならないことは、すべてのビュー データをビュー自体にカプセル化する方法を見つけることです。

この例は、2つのクラスを使用しています

  • テンプレート
  • テンプレートスコープ

テンプレート クラスの機能は、ドメイン ロジックがデータをビューに設定して処理するためのものです。

簡単な例を次に示します。

class Template
{
    private $_tpl_data = array();

    public function __set($key,$data)
    {
        $this->_tpl_data[$key] = $data;
    }

    public function display($template,$display = true)
    {
        $Scope = new TemplateScope($template,$this->_tpl_data); //Inject into the view
        if($display === true) 
        {
            $Scope->Display();
            exit;
        }
        return $Scope;
    }
}

これは、拡張できる非常に基本的なものです。スコープについてもそうです。これは基本的に、ビューがインタープリター内でコンパイルされるクラスです。これにより、TemplateScope クラス内のメソッドにアクセスできますが、スコープ クラスの外部にはアクセスできません。つまり、名前。

class TemplateScope
{
    private $__data = array();
    private $compiled;
    public function __construct($template,$data)
    {
        $this->__data = $data;
        if(file_exists($template))
        {
            ob_start();
            require_once $template;
            $this->compiled = ob_get_contents();
            ob_end_clean();
        }
    }

    public function __get($key)
    {
        return isset($this->__data[$key]) ? $this->__data[$key] : null;
    }

    public function _Display()
    {
        if($this->compiled !== null)
        {
             return $this->compiled;
        }
    }

    public function bold($string)
    {
        return sprintf("<strong>%s</strong>",$string);
    }

    public function _include($file)
    { 
        require_once $file; // :)
    }
}

これは基本的なものであり、機能していませんが、概念はそこにあります。使用例を次に示します。

$Template = new Template();

$Template->number = 1;
$Template->strings = "Hello World";
$Template->arrays = array(1,2,3,4)
$Template->resource = mysql_query("SELECT 1");
$Template->objects = new stdClass();
$Template->objects->depth - new stdClass();

$Template->display("index.php");

テンプレート内では、次のように従来の php を使用します。

<?php $this->_include("header.php") ?>
<ul>
    <?php foreach($this->arrays as $a): ?>
        <li><?php echo $this->bold($a) ?></li>
    <?php endforeach; ?>
</ul>

これにより、キーワードにアクセスできるテンプレート内にインクルードし、それ自体をインクルードすることもできます$this(再帰のようなものです)。

次に、キャッシュするものが何もないため、プログラムでキャッシュを作成しないでください。コンパイル/解釈時間の大部分をスキップして、コンパイル済みmemcachedのソースコードをメモリ内に保存するものを使用する必要があります。

于 2011-02-16T14:59:31.833 に答える
1

DOMXPath を使い始める前に、このようなちょっとしたことに対する非常に基本的な答えがありました。

クラスはこのようなものです(それがあなたが望むものとまったく同じように機能するかどうかはわかりませんが、非常に単純に機能するので考えてみてください

<?php
class template{
private $template;

function __CONSTRUCT($template)
{
    //load a template
    $this->template = file_get_contents($template);
}

function __DESTRUCT()
{
    //echo it on object destruction
    echo $this->template;
}

function set($element,$data)
{
    //replace the element formatted however you like with whatever data
    $this->template = str_replace("[".$element."]",$data,$this->template);
}
}
?>

このクラスでは、必要なテンプレートを使用してオブジェクトを作成し、set 関数を使用してすべてのデータを配置するだけです。

オブジェクトが作成された後の単純なループで、おそらく目標を達成できます。

幸運を

于 2011-02-16T14:53:04.810 に答える
1

キャッシングや、smarty のような確立されたテンプレート エンジンに向かわせるその他の高度なトピックについて心配していなければ、PHP 自体が優れたテンプレート エンジンであることがわかります。通常のようにスクリプトで変数を設定し、テンプレート ファイルをインクルードするだけです

$name = 'Eric';
$locations = array('Germany', 'Panama', 'China');

include('templates/main.template.php');

main.tempate.php は、PHP以外の人が使用するのが非常に簡単な代替の php タグ構文を使用します。php タグでラップされたものはすべて無視するように指示するだけです :)

<h2>Your name is <?php echo $name; ?></h2>
<?php if(!empty($locations)): ?>
  <ol>
    <?php foreach($locations as $location): ?>
    <li><?php echo $location; ?></li>
    <?php endforeach; ?>
  </ol>
<?php endif; ?>
<p> ... page continues ... </p>
于 2011-02-16T14:44:21.937 に答える
-4

スマーティー:) ...

php:

$smarty->assign("people",$peopleArray)

賢いテンプレート:

{foreach $people as $person}
<b>{$person.name}</b> {$person.surname}<br />
{/foreach}

やるべきことは他にもいくつかありますが、それが本質的に smarty のようなものです。

于 2011-02-16T14:32:11.500 に答える
-11

Smartyを使用します。

于 2011-02-16T14:32:04.407 に答える