在 PHP 中有没有更好的方法来做动态模板

In PHP is there a better way to do dynamic templating

我正在为一个应用程序创建模块,该应用程序将具有简单的自定义模板,其中包含将被数据库中的数据替换的标签。该模块的每个实例中的字段名称都不同。我想知道是否有更好的方法来做到这一点。

下面的代码是我想出的,但我相信一定有更好的方法。我在 preg_split 和 preg_match_all 上苦苦挣扎,刚刚达到我的极限,所以我用愚蠢的方式做到了。

<?php

$customTemplate = "
<div>
    <<This>>
    <<that>>
</div>
";

function process_template ($template, $begin = '<<', $end = '>>') {
    $begin_exploded = explode($begin, $template);
    if (is_array($begin_exploded)) {
        foreach ($begin_exploded as $key1 => $value1) {
            $end_exploded = explode($end, $value1);

            if (is_array($end_exploded)) {
                foreach ($end_exploded as $key2 => $value2) {
                    $tag = $begin.$value2.$end;
                    $variable = trim($value2);

                    $find_it = strpos($template,$tag);
                    if ($find_it !== false) {
                        //str_replace ($tag, $MyClass->get($variable), $template );
                        $template = str_replace ($tag, $variable, $template);
                    }
                }
            }
        }
    }
    return $template;
}


echo(process_template($customTemplate));

/* Will Echo 

<div>
    This
    that
</div>

*/
?>

以后我会连接 $MyClass->get() 来用正确的数据替换标签。自定义模板将由用户构建。

而不是 preg_splitpreg_match 我宁愿使用 preg_replace_callback,因为你正在做替换,替换值是从看起来最终将成为一种方法的东西派生的在另一个 class.

function process_template($template, $begin = '<<', $end = '>>') {
    // get $MyClass in the function scope somehow. Maybe pass it as another parameter?
    return preg_replace_callback("/$begin(\w+)$end/", function($var) use ($MyClass) {
        return $MyClass->get($var[1]);
    }, $template);
}

这里有一个可以玩的例子:https://3v4l.org/N1p03

我想这只是为了 fun/learning。如果我真的需要为某些事情使用模板,我宁愿从 composer require "twig/twig:^2.0" 开始。事实上,如果你有兴趣了解更多关于它是如何工作的,你可以去看看一个完善的系统,比如 twig 或 blade。 (Better than I've done it in this answer.)

周围有大量的模板引擎,但有时...只是为一件可能很简单的事情增加了复杂性和依赖性。这是我用来进行一些 javascript 更正的修改示例。这适用于您的模板。

function process_template($html,$b='<<',$e='>>'){
    $replace=['this'=>'<input name="this" />','that'=>'<input name="that" />'];
    if(preg_match_all('/('.$b.')(.*?)('.$e.')/is',$html,$matches,PREG_SET_ORDER|PREG_OFFSET_CAPTURE)){
      $t='';$o=0;
      foreach($matches as $m){
        //for reference $m[1][0] contains $b, $m[2][0] contains $e
        $t.=substr($html,$o,$m[0][1]-$o);
        $t.=$replace[$m[2][0]];
        $o=$m[3][1]+strlen($m[3][0]);
      }
      $t.=substr($html,$o);
      $html=$t;
    }
    return $html;
}
$html="
<div>
    <<this>>
    <<that>>
</div>
";
$new=process_template($html);
echo $new;

出于演示目的,我放置了处理替换的数组 $replace。您将那些替换为将处理替换的函数。

这是一个工作片段:https://3v4l.org/MBnbR

我喜欢这个功能,因为您可以控制在最终结果中替换什么和放回什么。顺便说一下,通过在正则表达式组出现的位置上使用 PREG_OFFSET_CAPTURE 和 return。那些在 $m[x][1] 上。捕获的文本将在 $m[x][0].