【问题标题】:if and foreach in a templating engineif 和 foreach 在模板引擎中
【发布时间】:2014-05-18 11:01:35
【问题描述】:

我正在开发一个模板引擎(我不想使用已经存在的引擎),它运行良好。这是我现在的代码:

class template {

    private $vars = array();
    public $page;

    function __construct() {
    }

    public function render($render = false) {
            $page = $this->page . '.php';
            $content = file_get_contents($page);

            foreach ($this->vars as $key => $value) {
                $tag = '{' . $key . '}';
                $content = str_replace($tag, $value, $content);
            }

            if ($render)
                echo $content;
            else
                return $content;
    }

    public function assign($key, $value, $overwrite = false) {
        if ($overwrite) {
            $this->vars[$key] = $value;
        } else if (isset($this->vars[$key])) {
            echo 'this var already exists!';
        } else {
            $this->vars[$key] = $value;
        }
    }

    public function append($key, $value) {
        $this->vars[$key] .= $value;
    }

    public function setPage($page) {
        $this->page = $page;
    }

}

但我想知道如何将 if & else 和 foreach 循环添加到引擎中。我希望它在 html 中看起来像这样:

<!DOCTYPE html>
<html>
    <head></head>        
    <body>
        [@if {bool} == true][ <!-- different expressions like {int} > 2 should work too -->
            <div>{text}</div>
        ]
        [@else][
            <div> error </div>
        ]

        [@foreach {jsLinks} as {jsLink}][
            <script type="text/javascript" src="{jsLink}"></script>
        ]
    </body>
</html>

模板文件保存为 .php 文件,所以我可以这样做&lt;?php if($bool == true){?&gt; some html &lt;?php }?&gt;, 但我不想在模板文件中使用 php 代码。 谁能帮我解决这个问题?

编辑

我添加了这段代码:

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

还有这两个功能:

private function wrap($element){
    $this->stack[] = $this->vars;
    foreach ($element as $k => $v) {
        $this->vars[$k] = $v;
    }
}

private function unwrap() {
    $this->vars = array_pop($this->stack);
}

但这只是在浏览器中回显&lt;?php foreach ($this-&gt;vars[\'$1\'] as $ELEMENT): $this-&gt;wrap($ELEMENT); ?&gt;&lt;?php $this-&gt;unwrap(); endforeach; ?&gt;。有什么办法解决这个问题?

编辑:我做到了!

我现在可以在我的模板中使用 foreach 循环以及 if 和 else。我的模板类:

<?php

class Template {

    private $vars = array();
    public $page;
    public $view;
    public $bDisplay = true;

    function __construct($view = false) {
        $this->view = $view;
    }

    public function render($render = false) {
        if ($this->bDisplay === true) {
            $page = PATH_VIEWS . $this->page . '.php';
            $page = (empty($this->page) ? ($this->view ? PATH_VIEWS . $this->view . DS . 'index.php' : PATH_VIEWS . 'index' . DS . 'index.php') : (file_exists($page) ? $page : PATH_VIEWS . 'index' . DS . 'index.php'));
            $content = file_get_contents($page);

            $content = $this->replace($content, $this->vars);

            $content = preg_replace('~\{LOOP:(\w+)\}~', '<?php foreach ($this->vars[\'$1\'] as $value){ echo  $this->replace(\'', $content);
            $content = preg_replace('~\{ENDLOOP:(\w+)\}~', '\', $value);} ?>', $content);

            $content = preg_replace('~\{IF:([^\r\n}]+)\}~', '<?php if ($1): echo \'', $content);
            $content = preg_replace('~\{ELSE\}~', '\'; else: echo \'', $content);
            $content = preg_replace('~\{ENDIF\}~', '\'; endif; ?>', $content);


            if ($render)
                eval('?>' . $content . '<?php');
            else
                return $content;
        }
        else {
            return false;
        }
    }

    private function replace($content, $vars) {
        foreach ($vars as $key => $value) {
            if (!is_array($vars[$key])) {
                $tag = '{' . $key . '}';
                $content = str_replace($tag, $value, $content);
            }
        }

        return $content;
    }

    public function assign($key, $value, $overwrite = false) {
        if ($overwrite) {
            $this->vars[$key] = $value;
        } else if (isset($this->vars[$key])) {
            echo 'this var already exists!';
        } else {
            $this->vars[$key] = $value;
        }
    }

    public function append($key, $value) {
        $this->vars[$key] .= $value;
    }

    public function addArray($array, $key, $value) {
        $this->vars[$array][][$key] = $value;
    }

    public function setPage($page) {
        $this->page = $page;
    }

}

?>

以模板为例:

<!DOCTYPE html>
<html>
    <head></head>
    <body>
        <!-- foreach loops -->
        {LOOP:js}
        <script type="text/javascript" src="{link}"></script>
        {ENDLOOP}

        <!-- if statement -->        
        {IF: {bool} === true}
        display some text
        {ENDIF}

        <!-- if-else statement -->        
        {IF: {number} > 2}
        number is bigger than 2
        {ELSE}
        number is smaller than 2
        {ENDIF}

    </body>
</html>

【问题讨论】:

  • 您需要实现一个解析器,或者更好的转换器,并将其注册为这些模板文件的处理程序。您可能想查看在 unixoid 系统上常见的“编译器编译器”:bisonyacc

标签: php html if-statement foreach template-engine


【解决方案1】:

唯一的办法就是写转换器。例如,解析模板并将[@if {bool} == true] 转换为&lt;?php if ($bool == true): ?&gt;

【讨论】:

  • 我该怎么做?用正则表达式?
  • 另外,看这里github.com/fabpot/Twig/blob/master/lib/Twig/… 第一条评论说解析器使用“优先级攀升”算法。
  • 但是,我可以使用什么代码来执行此操作?你能举个例子吗?
  • @Johan 这不是一个简单的话题。您仍然需要解析表达式以了解符号是变量还是文字等。如果您停留在最简单的构造('if')上,最好坐下来重新考虑一下您在做什么。调查 Twig 的来源将是一个很好的起点。另请注意,PHP 本身是一个模板引擎(功能强大)。
猜你喜欢
  • 2012-09-04
  • 1970-01-01
  • 2012-10-19
  • 1970-01-01
  • 2012-11-01
  • 2013-04-12
  • 2017-07-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多