【问题标题】:PHP - Creating a custom templatesystem?PHP - 创建自定义模板系统?
【发布时间】:2010-12-04 14:24:39
【问题描述】:

我已经在这里搜索过,但令人惊讶的是我没有找到答案。我找到了一个类似的线程,但那里没有真正的解决方案。复杂的部分是循环,如果我不需要循环,我可以定期替换。

所以,我有一个带有一些标记的 .html 文件,如下所示:

<ul>
    {{startloop}}
    <li>
        <img src="/album/{{filename}}" alt="">
        <span>{{imgname}}</span>
    </li>
    {{endLoop}}
</ul>

我想要做的是将 {{filename}} 和 {{imgname}} 替换为其他内容。我知道该怎么做,但问题是,我希望它在一个循环中。所以对于每个循环的项目 {{filename}} 和 {{imgname}} 将是不同的。如果我有两个“项目”,它看起来像这样(只是一个例子):

<ul>
    <li>
        <img src="/album/image1.jpg" alt="">
        <span>Test name 1</span>
    </li>
    <li>
        <img src="/album/image2.jpg" alt="">
        <span>Test name 2</span>
    </li>
</ul>

有什么建议吗?

【问题讨论】:

  • 您是否已经尝试过一些代码?请添加示例代码和输出。
  • 您是否注意到这个“模板引擎”仅将&lt;?=$(或&lt;?php echo $ 替换为{{ 和`?>` 替换为}}?你只是在制造许多新问题而是解决任何问题。
  • 只要你要问这样的问题,你就不应该去设计自己的模板系统,而​​应该重用一些由经验丰富的开发人员构建的现有模板系统。
  • PHP 是一个模板系统。使用 PHP。你不能用 PHP 编写比 PHP 本身更好的模板系统。

标签: php templates loops


【解决方案1】:

很长一段时间以来,我都是“智能”模板引擎的忠实粉丝,直到我意识到我根本不需要它 :) 使用直接内联 php 标签会更好更快。

只需将 html+php_tags 放入“some_template.inc”文件而不是 html 文件。

然后通过“include('template.inc');”显示这个模板

'template.inc' 示例:

<ul>
    <?foreach ($items as $item){?>
    <li>
        <img src="/album/<?=$item[filename]?>" alt="">
        <span><?=$item[imgname]?></span>
    </li>
    <?}?>
</ul>

【讨论】:

  • 设计师对此并不擅长。为什么用 PHP 代码信任他们?!到目前为止,我的建议是始终始终使用 PLAIN TEXT 模板。
  • 另一方面 - smarty 模板引擎是为了简化设计师的生活。但是它的标签 {foreach from=... item=...} 并不比 简单多少,那么为什么要使用 smarty 或任何其他模板引擎呢?我想设计师不会笨到不能学习一些主要的 php 标签:) PLAIN TEXT 模板是什么意思?
【解决方案2】:

不要创建一个完全没有意义的解析器,PHP 已经是一个模板引擎,你要做的就是用封装的模板系统扩展它的功能。

下面的方法是我一直创建模板引擎的方式,它非常失败,并且可以使用模板助手进行扩展。

我的模板系统的一个好处是,与 smarty 等引擎相比,您不必浪费资源为已编译的模板创建缓存系统,因为那里已经处于编译状态。

首先我们要创建一个主模板类,用于设置数据,选择模板等。

让我们开始吧:

class Template
{
    private $__data = array();

    public function __construct(){/*Set up template root here*/}

    public function __set($key,$val)
    {
        $this->__data[$key] => $val;
    }

    public function __get($key)
    {
        return $this->__data[$key];
    }

    public function Display($Template)
    {
        new TemplatePage($Template,$this->__data); //Send data and template name to encapsulated object
    }
}

这是一个非常基本的类,它允许做类似的事情

$Template = new Template();

$Template->Userdata = $User->GetUserData();

$Template->Display("frontend/index");

好的,现在您可能已经注意到上面的类TemplatePage,这是加载实际文件模板的类,在实际模板中,您将在TemplatePage 范围内。

这将允许您拥有获取模板数据和访问帮助器的方法,下面是 TemplatePage 的示例

class TemplatePage
{
    private $__data = array();

    public function __construct($template,$data)
    {
        $this->__data = $data;
        unset($data);

        //Load the templates
        if(file_exists(TEMPLATE_PATH . "/" . $template . ".php"))
        {
            require_once TEMPLATE_PATH . "/" . $template . ".php";
            return;
        }
        trigger_error("Template does not exists",E_USER_ERROR);
    }

    public function __get($key)
    {
        return $this->__data[$key];
    }

    public function require($template)
    {
        if(file_exists(TEMPLATE_PATH . "/" . $template . ".php"))
        {
            require_once TEMPLATE_PATH . "/" . $template . ".php";
            return;
        }
        trigger_error("Template does not exists",E_USER_NOTICE);
    }

    public function link($link,$title)
    {
        return sprintf('<a href="%s">%s</a>',$link,$title);
    }
}

所以现在模板在类的范围内加载,您可以扩展linkrequire 等方法以获得功能齐全的模板工具包

模板示例:

<?php $this->require("folder/js_modules") ?>
<ul>
    <?php foreach ($this->photos as $photo): ?>
    <li>
        <?php echo $this->link($photo->link,"click to view") ?>
        <span><?php echo $photo->image_name?></span>
    </li>
    <?php endforeach; ?>
</ul>
<?php $this->require("folder/footer") ?>

【讨论】:

  • +1 表示“使用 PHP”。此外,请勿在您的姓名中使用双下划线前缀。它们是为 PHP 保留的。
  • @Meagar,首先这是赞成票,使用双下划线在这里没有任何影响,因为首先有变量,我不认为 PHP 有任何魔法变量,其次我专门查看对象范围,即$this-&gt;,下划线的原因是因为有一种将数据设置为数组的神奇方法,我不希望用户设置名为数据的内容,因为它会覆盖容器。
【解决方案3】:

您有什么理由制作自己的模板系统吗?我建议使用 Smarty http://www.smarty.net/

它已经拥有这个功能以及更多,比如缓存等。

【讨论】:

  • 我想在这个项目中自己创建所有东西,这应该不是那么难,对吧?我的意思是,它看起来并不复杂——只是想办法做到这一点。在我的项目中使用 smarty 之类的模板引擎也感觉没有必要。对于我需要的东西来说,它太大了。
  • @ajreal Django 模板、Mustache 和其他几个模板系统也使用双花括号语法。
  • @asdf:“这不应该真的那么难”是过于乐观,如果不是短视的话。你还没有进入条件和其他类型的循环。
  • @stillstanding:乐观是好事。而且我仍然相信这并不难,可能有很多不同的解决方案,其中一些会很简单。 @ajreal:我有充分的理由使用它。所以你是说人们不能问简单的问题?
  • @asdf 加油,这是一个很棒的练习。它有多难取决于功能。但不要认为支持表达式是一件容易的事——非常重要。尤其是不使用 PHP/eval。
【解决方案4】:

也许在这里做的更好的事情是使用 MVC/MVVVM 模式,然后您可以免费获得它以及一个非常结构化和有组织的代码项目。

查看 Rasmus 博客中的此页面作为此工作流程的入门: http://toys.lerdorf.com/archives/38-The-no-framework-PHP-MVC-framework.html

如果您愿意放手一点,Zend 作为一个非常好的框架,可以帮助您快速完成您的网站。它将使您不必自己重写大量代码,并为您提供一些您可能不想自己编写的高级功能。

对于某些框架的大小,我完全同意你的看法,没有它们你也可以做到这一点。权衡是时间。编码时间和调试时间。就像我说的,如果您愿意放弃一些控制权,您可以轻而易举地完成您的项目,只需处理调试站点的“业务逻辑”,而不必重新发明大量现有代码。

希望这有帮助。

【讨论】:

    【解决方案5】:

    创建超快模板系统的唯一方法是依赖 PHP 作为解析器,或者通过使用用 C 编码的扩展。此外,在任何情况下都可能没有理由尝试这样做,因为它已经完成了一千次。有很多像 Smarty 这样的大赢家,尽管性能并不出色。 PHPBB 中的模板系统也很不错(使用预解析和缓存的 PHP)。避免在这里重新发明轮子。

    如果性能是一个主要问题,我强烈推荐Blitz

    PHPBB 借是另一条路线。如果您无权在您的服务器上扩展 PHP,并且 Smarty 不是您在性能格式方面的首选,并且想要所有的裸机代码,您可以像我一样删除 PHPBB 中的内容。这不是最终的解决方案,并且充满了细节,但它非常好——而且有了源代码,您可以根据自己的喜好对其进行定制。它 eval 编码,因此支持某种级别的表达式,并支持 HTML 注释标记作为模板转义/标记,这对于技术水平较低的图形设计师来说是用户友好的。

    【讨论】:

      【解决方案6】:

      将您的 {{tags}} 替换为 php 代码块(在本例中为 foreach),然后将结果替换为 eval。这就是 php 模板引擎的工作原理。

      示例:

      $template = "<h1>Hello {{name}}</h1>";
      $name = "Joe";
      
      $compiled_template = preg_replace(
          '~{{(.+?)}}~', 
          '<?php echo $$1 ?>', 
          $template);
      
      eval('?>' . $compiled_template);
      

      打印&lt;h1&gt;Hello Joe&lt;/h1&gt;

      一个更高级的例子,涉及数组和循环

      $template = "
          {{each user}}
              {{name}} {{age}}<br>
          {{end}}
      ";
      
      $user = array(
          array('name' => 'Joe', 'age' => 20),
          array('name' => 'Bill', 'age' => 30),
          array('name' => 'Linda', 'age' => 40),
      );
      
      $t = $template;
      
      $t = preg_replace(
          '~{{each (\w+)}}~', 
          '<?php foreach($$1 as $item) { ?>', 
          $t);
      
      $t = preg_replace(
          '~{{end}}~', 
          '<?php } ?>', 
          $t);
      
      $t = preg_replace(
          '~{{(\w+)}}~', 
          '<?php echo htmlspecialchars($item["$1"]) ?>', 
          $t);
      
      eval('?>' . $t);
      

      回应其他 cmets,告诉我“php 是模板引擎”和“eval 是邪恶的”——人们,不要重复你在某处听到的愚蠢的咒语。试着自己思考。

      【讨论】:

      • 我想到了类似的东西,但由于它周围的 html 代码,我没有设法 eval() 它。那将如何运作?例子?
      • 对每次编译模板并使用eval()的疯狂想法投反对票。
      • @stereofrog,确实有效。但是在您的第一篇文章中,您建议我添加大量 php 代码(例如 ),然后对其进行评估。编辑您的帖子后,您只需将 {{name}} 替换为 $name。正如我之前所说,关于这个的复杂部分是让它运行一个循环。你能给我一个更好的例子来运行一个循环并回显一个数组吗?非常感谢! @Col;你经常评论别人的建议,但你从不提供帮助。这是为什么呢?
      • 天哪,谁会做这样的事情:(,永远不应该使用这个,尤其是在模板系统中.. -1
      • "eval is evil" 仅当它影响性能并且输入来自最终用户时。显然,模板不是最终用户提供的。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多