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

标签 php html 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>

模板本身可能看起来像这样:

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

除了 Page 和 Content/Container 标签之外,核心中还包含一些其他标签,用于流量控制、遍历集合、输出动态值等。该框架的设计使其非常容易添加您的在另一个前缀和 namespace 下注册的自己的一组标签。

自定义标签到 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(); ?>

好的、坏的和eval

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

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

问题

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

  • 总体思路(html/php 的自定义标签)
  • 将标签转换成php代码而不是直接处理
  • 基于堆栈的方法
  • eval(或类似的)的使用

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

最佳答案

让我提倡一种不同的方法。与其动态生成 PHP 代码然后尝试弄清楚如何安全地执行它,不如在遇到标记时直接执行它。您可以一次处理整个 HTML block ,并在遇到每个标记时立即处理

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

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

使用这种方法,您只需直接调用 PHP 函数,您永远不会即时构建 PHP 代码,然后再执行它。不再需要 eval

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

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

关于PHP - 使用自定义标签进行模板化 - 这是对 eval 的合法使用吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3326446/

相关文章:

mysql - mysql中如何使用动态变量(变量名包含变量)

php - sqlite登录表单无法正常工作

javascript - Backbone.js 根据所选下拉列表更改文本

html - block 充当内联 block ?

javascript - 通过字符串值引用 javascript 对象 - 不使用 eval()

Python 3.5 如何摆脱类函数中的 eval

php - 使用 PHP 解析来自 WSDL 的响应

php - CodeIgniter 输出缓存如何工作?

PHP 在数据库中的分页表中排序

javascript - 防止子元素在子菜单项单击时触发父事件