本文介绍了PHP循环模板引擎-从头开始的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

对于一个小组项目,我正在尝试为PHP的用户创建模板引擎,这些人对该语言缺乏经验的人可以在HTML中使用{name}之类的标签,而PHP会使用数组中的预定义变量替换该标签.以及支持循环.

For a group project I am trying to create a template engine for PHP for the people less experienced with the language can use tags like {name} in their HTML and the PHP will replace that tag with a predefined variable from an array. As well as supporting loops.

这远远超出了项目的期望,但是根据我对PHP的经验,我认为让我保持忙碌是一个很好的挑战!

This is well beyond the expectations of the project, but as I have experience with PHP I thought it would be a good challenge to keep me busy!

我的主要问题是,如何执行解析器的循环部分,这是实现这种系统的最佳方法.在您推荐现有模板系统之前,我宁愿自己为经验创建它,因为我们项目中的所有内容都必须是我们自己的.

My main questions are, how do I do the loop part of the parser and is this the best way to implement such a system. Before you just recommend an existing template system, I would prefer to create it myself for experience and because everything in our project has to be our own.

目前,使用regex和preg_replace_callback完成基本解析时,它会检查$ data [name]是否存在,并替换它.

At the moment the basic parsing is done with regex and preg_replace_callback, it checks if $data[name] exists and if it does replaces it.

我尝试过各种不同的循环方式,但是不确定我是否走在正确的轨道上!

I have tried to do the loop a variety of different ways but am not sure if I am on the correct track!

如果给出了解析引擎的数据,则示例为:

An example if the data the parsing engine was given is:

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
)

它正在解析的页面是这样的:

And the page it was parsing was something like:

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

它会产生类似于以下内容的东西:

It would produce something similar to:

<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>

与此相伴,您的时间令人难以置信!

Your time is incredibly appreciated with this!

非常感谢,

P.s.我完全不同意这一点,因为我希望创建与经验已经存在的东西类似的东西,所以我格式合理且易于理解的问题会被否决.

P.s. I completely disagree that because I am looking to create something similar to what already exists for experience, my well formatted and easy to understand question gets down voted.

P.p.s似乎该主题的观点广为传播,请不要压倒人们,因为他们对您有不同的观点.每个人都有自己的权利!

P.p.s It seems there is a massive spread of opinions for this topic, please don't down vote people because they have a different opinion to you. Everyone is entitled to their own!

推荐答案

一种简单的方法是将模板转换为PHP并运行它.

A simple approach is to convert the template into PHP and run it.

$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标签.

For example, this converts the template tags to embedded PHP tags.

您将看到我引用了$this->showVariable()$this->data$this->wrap()$this->unwrap().这就是我要实现的.

You'll see that I made references to $this->showVariable(), $this->data, $this->wrap() and $this->unwrap(). That's what I'm going to implement.

showVariable函数显示变量的内容.每次迭代都会调用wrapunwrap来提供闭包.

The showVariable function shows the variable's content. wrap and unwrap is called on each iteration to provide closure.

这是我的实现方式

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()unwrap()函数中,我使用堆栈来跟踪变量的当前状态.精确地,wrap($ELEMENT)将当前数据保存到堆栈中,然后将$ELEMENT中的变量添加到当前数据中,然后unwrap()从堆栈中恢复数据.

In wrap() and unwrap() function, I use a stack to keep track of current state of variables. Precisely, wrap($ELEMENT) saves the current data to the stack, and then add the variables inside $ELEMENT into current data, and unwrap() restores the data from the stack back.

为了提高安全性,我添加了以下额外内容以用PHP echos替换<:

For extra security, I added this extra bit to replace < with PHP echos:

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

基本上是为了防止直接注入<?<%<script language="php">的任何PHP代码.

Basically to prevent any kind of injecting PHP codes directly, either <?, <%, or <script language="php">.

用法是这样的:

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

这不是最好的方法,但这是可以完成的一种方法.

This isn't the best method, but it is one way it could be done.

这篇关于PHP循环模板引擎-从头开始的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-19 12:42