【问题标题】:What is the best way to insert HTML via PHP?通过 PHP 插入 HTML 的最佳方法是什么?
【发布时间】:2008-11-04 09:31:17
【问题描述】:

从“最佳实践”的角度来说,您认为使用 PHP 插入 HTML 的最佳方式是什么。目前我使用以下方法之一(主要是后者),但我很想知道您认为哪种方法最好。

<?php
  if($a){
?>
[SOME MARKUP]
<?php
  }
  else{
?>
[SOME OTHER MARKUP]
<?php
  }
?>

反对:

<?php
  unset($out);
  if($a) $out = '[SOME MARKUP]';
  else $out = '[OTHER MARKUP]';
  print $out;
?>

【问题讨论】:

    标签: php html template-engine


    【解决方案1】:

    如果你打算那样做,你想把你的逻辑和设计分开,真的。

    但您不需要使用 Smarty 来执行此操作。

    优先级是关于心态。我看到有人在 Smarty 中做了令人震惊的事情,最终变成了在 Smarty 中开发网站的人,然后一些明亮的火花会决定他们需要在 Smarty 中编写模板引擎(永远不要低估一个愚蠢的想法)。

    如果您将代码分成两部分并强迫自己遵守标准,那么您将获得更好的性能。

    PageLogic.php

    <?php 
    
      $pageData = (object)(array());  // Handy trick I learnt. 
    
      /* Logic Goes here */
    
    
     $pageData->foo = SomeValue; 
    
     ob_start(); 
     require("layout.php"); 
     ob_end_flush();
    

    布局.php

     <html>
       <!-- etc -->
       <?php for ( $i = 1; $i < 10; $i++ ){ ?>
        <?php echo $pageData->foo[$i]; ?>
       <?php } ?>
       <!-- etc -->
    </html>
    

    PHP 是作为模板引擎编写的,因此在评估是否需要深入研究 Smarty 之前,您至少应该尝试将其用于其设计任务。


    此外,如果您决定使用模板引擎,请尝试使用 默认 转义 HTML 的引擎,然后您“选择退出”而不是“选择加入”。你会为自己省去很多 XSS 的麻烦。 Smarty 在这方面比较薄弱,正因为如此,里面写了很多 content-naïve 的模板。

    {if $cond}
        {$dangerous_value}
    {else}
        {$equally_dangerous_value}
    {/if}
    

    通常是 Smarty 模板的运行方式。问题是 $dangerous_value 可以是任意 HTML,这只会导致甚至更多糟糕的编码实践,到处都是无法追踪的意大利面条代码。

    您认为应该的任何模板语言都可以解决这个问题。例如:

    {$code_gets_escaped} 
    {{$code_gets_escaped_as_a_uri}}
    {{{$dangerous_bare_code}}}
    

    通过这种方式,您的潜在利用途径在模板中很容易识别,而利用途径是 DEFAULT 行为。

    【讨论】:

    • 也可以做$pageData = new stdClass();,和(object)(array());一样
    • @tom,是的,奇怪的是,(对象)表示法更快:)。但为什么会这样,我不知道。
    • 1060K 次/秒 vs 819K 次/秒奇数。
    • 这对于每个页面请求执行一次的任务非常重要。 :D(对象)表示法很奇怪,可能大多数 PHP 开发人员都不知道。
    • 真正具有讽刺意味的是我在'new stdClass'符号之前发现了(对象)符号。
    【解决方案2】:

    -1 用于典型的歇斯底里的“改用 [我最喜欢的模板系统]!”帖子。每个 PHP 帖子,即使原生 PHP 答案是单行的,也总是退化成这样,就像每个单行 JavaScript 问题最终都充满了“改用 [我最喜欢的框架]!”。好尴尬。

    说真的,我们知道分离业务逻辑和表示关注点。您可以在任何模板系统中这样做 — 或这样做 — 在任何模板系统中,无论是 PHP、Smarty 还是完全不同的东西。没有任何模板系统可以在不经过大量思考的情况下神奇地将您的关注点分开。

    (事实上,限制性太强的模板系统最终可能会导致您不得不编写纯粹的展示性辅助代码,从而将您的业务逻辑与展示性问题混淆。这不是胜利!)

    要回答所提出的问题,第一个示例还可以,但由于缩进不好,很难阅读。请参阅 monzee 的示例以获得更易读的方式;您可以使用 : 表示法或 {},无论您喜欢哪个,但重要的是可读性是保持您的 HTML 和 PHP 作为一个单一的、“格式良好”的缩进层次结构。

    最后一个请求:记住 htmlspecialchars()。每次纯文本需要进入网页时,这个必须被使用,否则它就是XSS。我知道这个问题与此没有直接关系,但是每次我们发布包含 的示例代码或没有转义的等效框架时,我们都在鼓励继续安全灾难区域大多数 PHP 应用程序都已成为。

    【讨论】:

    • 我非常同意您不需要模板引擎,但问题是关于最佳实践,其中最重要的一个是业务逻辑和表示的分离。你可能对他们了如指掌,但这并不意味着海报知道。
    • 我写我的答案时总是假设发帖者不知道,更重要的是,这个 WIKI 的许多未来读者不会知道!
    【解决方案3】:

    最重要的考虑是保持逻辑与表示分离 - 更少的耦合将使未来对两者的更改更加直接。

    您甚至可以考虑使用某种模板系统,例如 smarty

    【讨论】:

    • 链接已被删除。
    • @MalusJan 谢谢,我已经删除了已删除问题的链接。但总的来说(假设您有编辑权限)然后继续编辑 - 没有人会介意!
    【解决方案4】:

    对于这样一个非常简单的情况,使用 PHP 作为模板就可以了。但是,如果您超越了简单的逻辑(而且您很可能会这样做),那么使用模板引擎是一个好主意。

    在默认使用 PHP 视图脚本的 Zend Framework 中,推荐的方法如下:

    <?php if ($a) : ?>
        [MARKUP HERE]
    <?php else : ?>
        [SOME MORE MARKUP]
    <?php endif ?>
    

    更冗长的语法使得匹配条件块比使用大括号更容易。

    【讨论】:

    • 哦,说真的,“if : endif”样式是怎么回事? Joomla 1.5 源代码到处使用它,它让我发疯。括号简单易行,每个 IDE 都可以理解。
    • Joomla 没有世界上最好的代码,但使用条件的替代方式有时可以使代码更具可读性。
    • 它只适用于短代码块。一旦它变得太大,你会发现自己忘记关闭块,然后你的 IDE 就无法告诉你哪里出错了。 { } 永远! (红宝石弄错了)
    【解决方案5】:

    两者都不是。使用Smarty。通过将内部逻辑与显示逻辑分开,您将构建更易于维护的代码。 (不要走 PHPLib 的旧模板系统试图完全分离 PHP 和 HTML 的路径——它需要显示逻辑与您的核心业务逻辑混合在一起,并且非常混乱。)如果您绝对必须在您的PHP 代码,使用您的第二种方法,但将变量传递给 Smarty。

    【讨论】:

    • 您不需要 Smarty 来“将您的内部逻辑与显示逻辑分离”。 PHP 在这方面表现出色。
    【解决方案6】:

    最好使用模板引擎将逻辑(PHP 代码)与演示文稿(HTML)完全分离。

    将 PHP 插入 HTML 既快速又容易,但很快就会变得混乱,并且很难维护。这是一种非常快速且非常肮脏的方法...

    至于 PHP 中可用的所有模板引擎中哪个更好,例如,请参阅以下问题:

    【讨论】:

    • 恕我直言,这是最好的答案。尽管如此,对我来说,这取决于项目的规模。
    【解决方案7】:

    如果模板引擎看起来很麻烦,您可以制作自己的穷人模板引擎。此示例肯定需要改进,并不适合所有任务,但可能适合较小的站点。只是给你一个想法:

    模板.inc:

    <html><head><title>%title%</title></head><body>
    %mainbody%
    Bla bla bla <a href="%linkurl%">%linkname%</a>.
    </body></html>
    

    index.php:

    <?php
    $title = getTitle();
    $mainbody = getMainBody();
    $linkurl = getLinkUrl();
    $linkname = getLinkName();
    $search = array("/%title%/", "/%mainbody%/", "/%linkurl%/", "/%linkname%/");
    $replace = array($title, $mainbody, $linkurl, $linkname);
    $template = file_get_contents("template.inc");
    print preg_replace($search, $replace, $template);
    ?>
    

    【讨论】:

    • 不,不,不!您没有使用正则表达式,为什么要使用 preg_replace?改用 str_replace 会快得多。
    【解决方案8】:

    Smarty 没问题,如果您不使用框架或使用没有自己的模板系统的框架。

    否则大多数 PHP 框架和年轻一代的 CMS 都有自己的模板系统。

    一般来说,模板系统的想法是让文件几乎只包含 HTML(视图/模板文件)和只包含数据或业务逻辑(模型或控制器文件)的文件。

    模板文件可能如下所示(来自 SilverStripe 的示例):

    <?xml version="1.0" encoding="UTF-8"?>
     <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
        <head>
            <% base_tag %>
            $MetaTags
            <link rel="stylesheet" type="text/css" href="tutorial/css/layout.css" />
        </head>
        <body>
            <div id="Main">
                <ul id="Menu1">
                    <% control Menu(1) %>
                    <li class="$LinkingMode">
                        <a href="$Link" title="Go to the &quot;{$Title}&quot; page">$MenuTitle</a>
                    </li>
                    <% end_control %>
                </ul>
                <div id="Header">
                    <h1>$Title</h1>
                </div>
                <div id="ContentContainer">
                    $Layout
                </div>
                <div id="Footer">
                    <span>Some Text</span>
                </div>
            </div>
         </body>
    </html>
    

    您可以看到,在将页面发送到客户端之前,将插入数据的地方只插入了一些非 HTML 代码片段。

    然后,您的代码可以(简化)如下所示:

    <?php
      unset($out);
      if($a) $out = '[SOME CONTENT TO INSERT INTO THE TEMPLATE]';
      else $out = '[SOME ALTERNATIVE CONTENT]';
      templateInsert($out);
    ?>
    

    关于它的好处:您的 HTML 可以被这样看待和改变,您的设计人员可以理解它,并且不必查看您的代码试图将来自不同地方的点点滴滴放在一起,而无需有机会看看她在做什么。另一方面,您可以对逻辑进行更改,而不必担心它在页面上的外观。您很可能还会犯更少的错误,因为您的代码将是紧凑的,因此是可读的。

    【讨论】:

      【解决方案9】:

      我希望在我刚开始使用 PHP 时就知道的事情:让繁重的程序代码尽可能远离 HTML 输出。这样一来,它们都保持在大的、相当连续的、可读的块中。

      我发现这样做的最佳方法是首先制作一个静态 HTML 文件,可能包含一些假数据,这样我就可以四处寻找并正确设计,然后编写 PHP 代码获取输出的动态部分并将它们粘合在一起(你如何做这部分取决于你 - 你可以像其他人建议的那样用 Smarty 做)。

      【讨论】:

        【解决方案10】:

        如果你必须使用花括号。不要使用 PHP 回显 HTML。

        【讨论】:

          【解决方案11】:

          不要使用 smarty - PHP 本身就是一个模板系统。考虑使用这种语法:

          <?php if($a):?>
          [SOME MARKUP]
          <?php else: ?>
          [SOME OTHER MARKUP]
          <? endif; ?>
          

          【讨论】:

          • 我是从理论上的“最佳方式”的角度来询问的。
          • @tharkun:你能发布与这个例子等效的 smarty 代码吗?我很想看看它的可维护性和可扩展性有多少。
          • @Bobby Jack:我想请其他人发布 Smarty 代码,因为我没有使用 Smarty。
          • @tharkun:我想我的观点实际上比 smarty 更通用 - 你能说出 any 模板引擎,其中等效模板比上面的 PHP sn-吗?我不能,这就是为什么我站在“PHP 已经是一个模板引擎,让它完成它的工作”这一边的原因。人们使..
          • ... 100% 的布局与内容分离是可能的;过了一会儿,所有的模板引擎都变成图灵完备的了 :)
          猜你喜欢
          • 2014-12-14
          • 1970-01-01
          • 1970-01-01
          • 2010-10-07
          • 2011-01-07
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多