PHP - 使用自定义标签进行模板化 - 这是eval的合法使用吗?

Dag*_*bit 5 html php eval custom-tags

概观

大约2009年底,我写了一个简单的模板系统,在内部我们的设计师手册洁具型网站使用PHP/HTML.该系统的目标是通过PHP处理的自定义标记允许模板化其他纯HTML.例如,模板化页面可能如下所示:

<tt:Page template="templates/main.html">
  <tt:Content name="leftColumn">
    <p> blah blah </p>
    ...
  </tt:Content>
  <tt:Content name="rightColumn">
    <p> blah blah </p>
    ...
  </tt:Content>
</tt:Page>
Run Code Online (Sandbox Code Playgroud)

模板本身可能如下所示:

<html>
  <head>...</head>
  <body>
    <div style="float:left; width:45%">
      <tt:Container name="leftColumn" />
    </div>
    <div style="width:45%">
      <tt:Container name="rightColumn" />
    </div>
  </body>
</html>
Run Code Online (Sandbox Code Playgroud)

除了Page和Content/Container标签之外,核心中还包含一些其他标签,用于流控制,迭代集合,输出动态值等.框架的设计使得添加自己的一套很容易.标记在另一个前缀和命名空间下注册

自定义标签到PHP

我们如何解析这些自定义标签?由于无法保证HTML文件是格式良好的XML,因此XSLT/XPATH等解决方案将不可靠.相反,我们使用正则表达式来查找带有已注册前缀的标记,并用PHP代码替换它们.PHP代码是一个基于堆栈的设计...在遇到一个开始标记,表示创建该标记的物体压入堆栈,和它的"初始化函数"(如果有的话)延伸.每当遇到已注册的结束标记时,最新的对象将从堆栈中弹出,并且其"呈现函数"将运行.

因此,该框架替换PHP模板标签后,我们的示例页面看起来像这样(在房地产这有点丑陋):

<?php $tags->push('tt', 'Page', array('template'=>'templates/main.html')); ?>
  <?php $tags->push('tt', 'Content', array('name'=>'leftColumn')); ?>
    <p> blah blah </p>
    ...
  <?php $tags->pop(); ?>
  <?php $tags->push('tt', 'Content', array('name'=>'rightColumn')); ?>
    <p> blah blah </p>
    ...
  <?php $tags->pop(); ?>
<?php $tags->pop(); ?>
Run Code Online (Sandbox Code Playgroud)

好的,坏的,和 eval

现在,如何执行我们新生成的PHP代码?我可以在这里想到几个选项.最简单的是简单eval的字符串,这很好用.但是,任何程序员都会告诉你"eval是邪恶的,不要使用它......"所以问题是,有什么比eval我们在这里可以使用的更合适吗?

我考虑使用临时或缓存文件,使用php://输出流等,但据我所知,这些并没有提供任何真正的优势eval.缓存可以加快速度,但实际上我们对这个东西的所有站点已经非常快,所以我认为此时不需要进行速度优化.

问题

对于此列表中的每个事项:这是一个好主意吗?你能想到一个更好的选择吗?

  • 一般的整个想法(html/php的自定义标签)
  • 将标签转换为PHP代码而不是直接处理
  • 基于堆栈的方法
  • 使用eval(或类似)

感谢阅读和TIA的任何建议.:)

Joh*_*ica 2

让我提倡一种不同的方法。不要动态生成 PHP 代码,然后尝试找出如何安全地执行它,而是在遇到标签时直接执行它。您可以一次处理整个 HTML 块,并在遇到每个标签时立即对其进行处理。

编写一个查找标签的循环。它的基本结构如下所示:

  1. 查找位于n位置的自定义标签。
  2. 位置n之前的所有内容都必须是简单的 HTML,因此要么将其保存以进行处理,要么立即输出(如果堆栈上没有标签,$tags则可能不需要将其保存在任何地方)。
  3. 为标签执行适当的代码。无需生成调用的代码$tags->push,只需$tags->push直接调用即可。
  4. 返回步骤 1。

使用这种方法,您只需直接调用 PHP 函数,而无需即时构建 PHP 代码,然后再执行它。的需要eval已经消失了。

步骤#3 基本上有两种情况。当您遇到开始标签时,您将立即执行push. 然后,当您点击结束标记时,您可以执行 a pop,然后以适当的方式处理该标记,现在您已经处理了自定义元素的全部内容。

以这种方式处理 HTML 也更加高效。对长 HTML 字符串进行多次搜索和替换效率很低,因为每次搜索和每次替换字符串长度的复杂度都是 O( n )。这意味着您一遍又一遍地重复扫描字符串,每次进行替换时,您都必须生成长度相似的全新字符串。如果您有 20KB 的 HTML,则每次替换都需要搜索该 20KB,然后创建一个新的 20KB 字符串。