【问题标题】:Custom stream wrapper with include or eval?带有包含或评估的自定义流包装器?
【发布时间】:2012-10-12 09:07:08
【问题描述】:

概述

我目前正在编写模板引擎。它甚至支持多种“格式”。目前它可以解析.php文件和.tpl(特定于这个引擎)。

我会给你一个两者的小例子,只是为了给你一个想法。

template.php:

Name: <?php echo $this->h($name) ?>
Posts: 
<?php foreach($posts as $post): ?>
    - <?php echo $this->h($post->name) ?> (<?php echo count($post->comments) ?> comments)
      <?php echo $this->render('post/shortpost', array('post' => $post)) ?>
<?php endforeach ?>

这基本上只是一个标准的 PHP。

template.tpl

Name: {>$name}
Posts: 
{foreach($posts as $post):}
    - {>$post->name} ({=count($post->comments)} comments)
      {=:render('post/shortpost', array('post' => $post))}
{endforeach}

这个模板“语言”简单地被翻译成上面的 PHP。

比较

eval()

目前这些模板是使用 eval() 解析的。

专业版

  • 我不需要更改任何代码

对比

  • 当模板中发生错误时,您只会收到一条无用的错误消息,它不会 告诉你错误发生在哪个文件中,有时行号甚至是错误的。
  • 安全?模板文件只需要可读?
  • 很难调试代码。
  • 代码更难理解
  • 更多.. ?

流包装器和 include()

我最近读到了 php 中的流包装器。你甚至可以创建自己的。除了eval 之外的另一种解决方案是为每个模板“格式”创建一个自定义流包装器,并使用 include 来解析模板。

这有以下(潜在的)缺陷:

专业版

  • 可能会解决在错误消息中显示错误文件/行号的问题(有人遇到过这种情况吗?)
  • 您可以按照希望的方式处理模板文件。完全控制。

对比

  • allow_url_(fopen|include) 必须打开?
  • 很慢? (eval() 也很慢吗?)
  • 没有获得安全性。 include 的作用与 eval 基本相同。
  • 更多...?

编辑:缓存的解析文件和include()

第三种选择是将模板解析为 PHP 代码并缓存它们(如 @Jen-YaKovalev 所建议的那样)。

专业版

  • 包括缓存

对比

  • 如果在包含呈现的模板时发生错误并且发生错误 错误消息不会将您指向正确的文件/最终会显示给您 错误的行号。
  • 您需要一个额外的tmp/ 目录来保存已解析的文件。你需要写 PHP/网络服务器的权限。会更不安全,因为黑客 会更容易附加一些恶意代码。

编辑: 流过滤器和包含('php://filter')

最近发现了以下php.net页面:

这将是解决此问题的另一种可能性。使用include('php://filter/read=filtername/resource=file.php'),我可以包含一个文件,该文件将在执行之前首先通过过滤器filtername

专业版

  • 不需要像流包装器那么多的代码

对比

  • 没有像使用流包装器(缓存?)那样的可能性
  • 安全吗?
  • 速度?

问题

  • 有使用流包装器解析模板文件或类似文件的经验吗?
  • 还有其他解决方案吗?
  • 还有更多的专业人士和反对者吗?
  • 您会推荐哪一款?

【问题讨论】:

  • 我认为,这里最好的方法是缓存模板。您基本上生成 php 文件并执行它们。它还可以提高应用程序的性能和可扩展性。
  • eval 有 100 个缺点,我的意思是假设用户能够在评估之前将 PHP 字符串回显到您的模板中,因为使用了不同的缓冲区。通常人们会在这里使用正则表达式和其他解析函数来动态运行某些子句,它很慢,但它比流包装器稍微好一点。
  • @Jen-YaKovalev 我还可以使用 eval() 缓存已解析的模板并包含
  • @Sammaye include 与 eval() 几乎完全相同。 include "data:image/png;base64," . base64("&lt;?php // do badass stuff ?&gt;")
  • @BryanAllo 只是因为我可以。我做这个教育和乐趣。这也是我目前正在编码的框架的一部分。我不使用任何其他模板引擎,因为我可以自己做,我想自己做,而且我也有很多时间。我的依赖也少了。

标签: php eval template-engine stream-wrapper


【解决方案1】:

我认为这只是一个人的编码风格的味道,你最好投票它什么的。

  • 我个人认为 eval 是邪恶的(在所有语言中),
  • 在 include + php 包装器(甚至是集成的包装器*)方面有过不好的体验,
  • 知道所有大型(gish)模板系统都使用编译到一个 php 文件(smarty、twig),我会使用这个。

(*) 在早期的项目中,我们在 data-url 包装的包含中使用了 1 行代码(一个空的类扩展),它的性能很糟糕。

【讨论】:

  • 您在使用流包装器时遇到过哪些糟糕的体验? (什么是集成的?)。如果你能更具体一点就好了。
  • 问题是关于自定义流包装器,而不是关于数据 url(请参阅fr2.php.net/manual/en/function.stream-wrapper-register.php
  • 我知道,但我想我需要再说一遍。我的问题不是关于数据 url,而是关于 custom 流包装器。因此,您基本上编写了一个类似的类 (fr2.php.net/manual/en/stream.streamwrapper.example-1.php) 并使用 fr2.php.net/manual/en/function.stream-wrapper-register.php 将其注册为流包装器到“协议”var://。如果现在 URL 以 var:// 开头,则注册的类由 fopen()fread() 等函数调用。我可以做同样的事情来解析我的模板。问题是这有意义吗?
  • 正如我所写,您的所有选项都有意义,但根据我的经验,流包装器(自定义和内置的)可能很慢,我更喜欢编译/解析(这就是缓存的原因)文件,带有一个简单的包含。
【解决方案2】:

您当然不想在生产环境的每个请求中解析模板,这会浪费资源,因此是一种缓慢且不是非常聪明的方法,所以我强烈建议使用 缓存解析文件和 include() 方法。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-22
    相关资源
    最近更新 更多