+ -
当前位置:首页 → 问答吧 → 自己写的一个模板,想和大家讨论一下.

自己写的一个模板,想和大家讨论一下.

时间:2004-04-17

来源:互联网

思路:
    欲在速度和易用(主要指的是美工设计的方便性)之间取得一个平衡点.于是采用了由html文件生成php文件的办法(编译?)
    也想在分离显示逻辑和分离html代码之间平衡一下

例如一个论坛首页(index.php):

[Copy to clipboard] [ - ]
CODE:
<?php
require('./template.php');
//由html生成的php文件的前缀,区别使用多种风格.
$tpl_prefix = 'default';
//模板文件名
$tpl_index = 'index';

$tpl = new Template($tpl_prefix);

$cats = array(
    array('forum_id'=>;'1','forum_cat_id'=>;'0','forum_name'=>;'PHP学习'),
        array('forum_id'=>;'2','forum_cat_id'=>;'0','forum_name'=>;'MYSQL学习')
);
$forums = array(
        array('forum_id'=>;'3','forum_cat_id'=>;'1','forum_name'=>;'PHP高级教程'),
        array('forum_id'=>;'4','forum_cat_id'=>;'1','forum_name'=>;'PHP初级教程'),
        array('forum_id'=>;'5','forum_cat_id'=>;'2','forum_name'=>;'MYSQL相关资料')
);

if ($cats)
{
        if ($tpl->;chk_cache($tpl_index))//检查判断是否需要重新生产PHP模板文件.
    {
            $tpl->;load_tpl($tpl_index);//加载html模板文件.
                //替换PHP语句
                $tpl->;assign_block("{block_cat}","<?foreach(\$cats as \$cat) {?>;");
                $tpl->;assign_block("{/block_cat}","<?}?>;");
        $tpl->;assign_block("{block_forum}","<?foreach(\$forums as \$forum) {

\nif(\$forum['forum_cat_id'] == \$cat['forum_id']) {?>;");
            $tpl->;assign_block("{/block_forum}","<?}\n}?>;");
                //生产PHP模板文件.
                $tpl->;write_cache($tpl_index);
        }
}
//包含PHP模板文件.
include($tpl->;parse_tpl($tpl_index));
?>;

对应的html模板文件(index.html):

[Copy to clipboard] [ - ]
CODE:
{block_cat}
<table width="100%" border="0" cellspacing="1" cellpadding="1" bgcolor="#000000" align="center">;
  <tr align="{=TR_ALING}" bgcolor="#FFFFFF">;
    <td  colspan="6">;<span class="title">;<b>;{=$cat['forum_name']}</b>;</span>;</td>;
  </tr>;
{block_forum}
  <tr bgcolor="#FFFFFF">;
    <td valign="top">;{=$forum['forum_name']}</td>;
  </tr>;
{/block_forum}
</table>;
<br>;
{/block_cat}

经过处理,里面的{block_forum}{block_cat}标签被替换成PHP循环语句,用于显示数组种所有元素.

生成的PHP模板文件(default_index.php):

[Copy to clipboard] [ - ]
CODE:
<?foreach($cats as $cat) {?>;
<table width="100%" border="0" cellspacing="1" cellpadding="1" bgcolor="#000000" align="center">;
  <tr align="<?=TR_ALING?>;" bgcolor="#FFFFFF">;
    <td  colspan="6">;<span class="title">;<b>;<?=$cat['forum_name']?>;</b>;</span>;</td>;
  </tr>;
<?foreach($forums as $forum) {
if($forum['forum_cat_id'] == $cat['forum_id']) {?>;
  <tr bgcolor="#FFFFFF">;
    <td valign="top">;<?=$forum['forum_name']?>;</td>;
  </tr>;
<?}
}?>;
</table>;
<br>;
<?}?>;

default_index.php被包含在index.php,这样就可以正常显示了.

这样,HTML模板文件可以用dw来进行修改美化,美工人员应该会方便一些.
想听听大家的意见.

作者: lqpj   发布时间: 2004-04-17

由于是自己论坛使用的,所以只是想和大家讨论思路方面的问题.
水平问题,让大家笑话了
template.php

[Copy to clipboard] [ - ]
CODE:
<?php
/*********************************************************************************
*                                                                 模板类(Template)
*    最后修改时间:2004.4.07    本论坛使用   
*   
*
*
**********************************************************************************/
class Template {

        //$this->;$template,储存模板数据.
        var $template = '';

        //模板路径.
        var $tpl_path = '';

        //模板前缀(风格名称).
        var $tpl_prefix = '';

    //cache路径(编译后的路径).
        var $cache_path = '';
       
        //css文件路径.
        var $css_path = '';

        //header文件路径.
        var $header_path = '';

        //footer文件路径
    var $footer_path = '';

        /**
        * 初始化模板路径.
        */
        function Template($root = 'default')
        {
                //模板前缀(风格名称).
                $this->;tpl_prefix = $root;
                //模板文件路径.
                $this->;tpl_path = './templates/' . $root . '/';
                //生成的PHP文件存放路径.
                $this->;cache_path = './template_data/' .$this->;tpl_prefix . '_';
                return true;
        }

        /**
        * chk_cache,检查"编译"后的模板是否需要更新,判断依据:最后修改时间,"编译"文件是否存在.
        */
        function chk_cache($tpl_index)
    {
                $tpl_file = $this->;tpl_path . $tpl_index . '.html';
                $cache_file = $this->;cache_path . $tpl_index . '.php';
                //判断是否需要更新.
                if(!file_exists($cache_file))
        {
                        return true;
                }
        elseif(filemtime($tpl_file) >; filemtime($cache_file))
        {
                        return true;
                }
        }

        /**
        * 输出模板文件.
        */
        function parse_tpl($tpl_index,$message='')
    {
            return $this->;cache_path . $tpl_index . '.php';
    }

        /**
        * 加载模板文件.
        */
        function load_tpl($tpl_index)
    {
                $tpl_file = $this->;tpl_path . $tpl_index . '.html';
                $fp = fopen($tpl_file, 'r');
                $this->;template = fread($fp, filesize($tpl_file));
                fclose($fp);
        }

        /**
        * 替换变量,并且"编译"模板.
        */
        function write_cache($tpl_index)
    {
  
                $cache_file = $this->;cache_path . $tpl_index . '.php';

                //变量显示.
                $this->;template = preg_replace("/(\{=)(.+?)(\})/is", "<?=\\2?>;", $this->;template);

                //界面语言替换.
                $this->;template = preg_replace("/\{lang +(.+?)\}/ies", "\$lang['main']['\\1']", $this->;template);

        $fp = fopen($cache_file, 'w');
        flock($fp, 3);
        fwrite($fp, $this->;template);
        fclose($fp);
    }

        /**
        * 替换block.
        */
        function assign_block($search,$replace)
    {
                $this->;template = str_replace($search,$replace,$this->;template);
        }
}
?>;

作者: lqpj   发布时间: 2004-04-17

其实PHP本身就可以用来实现模板,
发现HTML模板里的{}不比php的& ?  ?>;简单多少。与其让美工去学习{}的模板,还不如让他学习使用PHP标注的模板.

这篇文章的讨论非常不错,几位都是大牛,你可以看看:http://bbs.chinaunix.net/forum/viewtopic.php?t=262364
可惜没有加精,建议斑竹加精,可能和标题有关


还有这篇文章:http://www.phpe.net/articles/384.shtml#template.zip
哪里都有。

作者: flytod   发布时间: 2004-04-17

这么老的帖子被我搜索"模板"时找出来了^_^

我仔细看了一下,大概领会到了楼主的思路
楼主能否分离提供一个可运行的示范文件?谢谢

作者: dianker   发布时间: 2004-06-10

好好好!!!

思路相当不错啊。呵呵,收藏了。

只是有一点相当怀疑:preg_replace()的效率高吗?

作者: tonera   发布时间: 2004-06-10

看看我的PHP模板,论坛列表页:

[Copy to clipboard] [ - ]
CODE:
<?php
    /*        不要修改和移动模板中的这个部分          */
    if (!defined("OPENMAIN"))
    {
        header("location: error.html");
    }
    global $boards, $parid, $moderators;
    /*        不要修改和移动模板中的这个部分          */
?>;

<!--  论坛列表模板开始  //--->;
<table align="center" width="500" border="0" cellspacing="1" cellpadding="4" class="forumlist">;
    <tr class="forummenu">;
        <td colspan="2" align="center">;Forum</td>;
        <td align="center">;Topics</td>;
        <td align="center">;Posts</td>;
        <td align="center">;Last Post</td>;
    </tr>;
    <!--  论坛分类开始  //--->;
<?php foreach ($boards[$parid] as $parBoard) { ?>;
    <tr class="category">;
        <td align="left" colspan="5">;<a href="<?=MAINPAGE?>;?mod=list&fid=<?=$parBoard["id"]?>;">;<?=$parBoard["title"]?>;</a>;</td>;
    </tr>;
    <!--  论坛分类结束  //--->;
    <!--  论坛子板块开始  //--->;
<?php foreach ($boards[$parBoard['id']] as $board) { ?>;
    <tr class="forum">;
        <td align="center" valign="middle" style="width:6%;" class="forumturn">;
        <img src="<?=IMAGEDIR?>;forum_active.gif" alt="活动论坛" />;</td>;
        <td align="left" valign="middle">;
        <a href="<?=MAINPAGE?>;?mod=list&fid=<?=$board["id"]?>;">;<?=$board["title"]?>;</a>;
        <br />;<?=$board["info"] ?>;
<?php if ($moderators[$board["id"]][0]["id"] != "") { ?>;
        <span style="font-size: 3px; line-height:3px;">;<br />;<br />;</span>;
        <b>;&Moderator : </b>;
<?php foreach ($moderators[$board["id"]] as $moderator) { ?>;
        <a href="<?=MAINPAGE?>;?mod=user&id=<?=$moderator["id"]?>;">;<?=$moderator["username"]?>;</a>;
<?php } ?>;
<?php } ?>;
        </td>;
        <td align="center" valign="middle" style="width:7%;" class="forumturn">;<?=$board["topics"]?>;</td>;
        <td align="center" valign="middle" style="width:7%;">;<?=$board["posts"]?>;</td>;
        <td align="center" valign="middle" style="width:25%;" class="forumturn">;<?=date("M d Y H:i:s", $board["lastPost"])?>;</td>;
    </tr>;
    <!--  论坛子板块结束  //--->;
<?php } ?>;
<?php } ?>;
</table>;
<!--  论坛列表模板结束  //--->;
<br />;

作者: 深空   发布时间: 2004-06-10

楼主的思路是需要的时候才生成新的模板 cache,所以 preg_replace 效率高不高都不太重要

反而是每次都要取两个文件的 filemtime,filemtime 的效率才是需要考虑的

其实可以在“后台”提交修改原始模板文件的时候就 cache 好,然后每次直接 include 就可以了

还有 $this->;assign_block($search,$replace) 的时候似乎可以用正则,做得扩展性和容错性更好一点

作者: 财狼   发布时间: 2004-06-11

也不知道是不是我的水平有点差,我看了一下楼主的源码,让我有点晕。我把程序运行了一下,广是说无法读取文件。去网上搜了一下关于模板的文章,可是也没有看懂,正在继续学习当中。。。
  
   为了让和我水平一样的朋友们可以和我一起学习讨论,我将文章做了些改动送给大家。有谁对它比较了解,请用白话说明。



作为一个PHP/Perl的程序员,许多模板引擎(fastTemplate, Smarty, Perl的

HTML::Template)的用户,以及我自己的(bTemplate [1] 的作者),我讲这句话

很多次了。

然而,在同事进行了长时间的讨论之后,我确信了大量的模板引擎(包括我自己

写的)根本是错误的。 我想唯一的例外是Smarty [2],虽然我认为它太庞大了

,并且考虑到这篇文章的其余部分相当的没有观点。然而,就你为什么选择

Smarty(或者类似的解决方案)有几个理由,这些将在文章后面探究。

这篇文章讨论模板的理论。我们将看到为什么大部分"模板引擎"是过于肥大,并

且最终我们将回过头来看一个轻量级的,小巧快速的另类选择。



下载和授权
模板类和所有在本文中使用的例子能够在这里下载:template.zip [3]。你可以

根据发布 [4]在 OSI [5] 的 MIT Open Source License使用这些文件中的代码





一些关于模板引擎的背景知识
让我们首先研究一下模板引擎的背景知识。模板引擎被设计出来用于把商业逻辑

(例如从数据库中获取数据或者计算贸易耗费)从数据的表现分离开来。模板引

擎解决了两个主要问题:


如何实现这种分离
如何从HTML中分离"复杂"的php代码

这从理论上使得没有PHP经验的HTML设计者能够不看任何PHP代码的条件下修改站

点的外观。

然而,模板系统也引入了一些复杂性。首先,我们现在有一个从多个文件得来的

"页面"。典型的,你可能有一个主PHP页负责业务逻辑,一个外面的"布局"模板

把整个站点的整体布局进行渲染,一个内部的内容特定的模板,一个数据库抽象

层,以及模板引擎本身(这些可能是也可能不是由多个文件组成)。也有可能,

一些人仅仅简单地在每个PHP页面的首尾处包含"头部"和"尾部"文件。

这产生的单个页面的文件数量是很可观的。然而,因为PHP解析器非常快,用到

的文件数量可能不是那么重要除非你的站点流量很大。
然而,要记住模板系统引入了另外一个处理的层次。模板文件不仅仅是必须被包

含,他们还必须被解析(取决于模板系统,这个行为有很多种方式来完成 ——

使用正则表达式,字符串替换,编译,词法分析,等等)。这就是为什么对模板

进行测速变得流行起来:因为模板引擎使用各种方法来解析数据,它们中的一些

比另外一些要快(而且,一些模板引擎提供了比其他引擎更加丰富的功能)。



模板引擎基础知识
简单地说,模板引擎利用了用C写的脚本语言(PHP)。在这些嵌入的脚本语言中

,你有另外一个伪脚本语言(无论你的模板引擎支持何种标签)。某些提供了简

单的变量改写和循环。另外一些呢,则提供了条件和嵌套循环。而再其他的呢(

至少有Smarty)提供了一个PHP的比较大的子集的接口,以及一个缓冲层。

为什么我认为Smarty最接近于正确的方向?因为Smarty的目标是"把业务逻辑从

表现中分离出来"而不是&quotHP代码和HTML代码的分离"。这看上去区别不大,但是

它正是要点所在。任何模板引擎的最终目标不应该是从HTML移除所有的逻辑。它

应该是把表现逻辑从业务逻辑中分离出来。

有很多你仅仅需要逻辑来正确显示你的数据的例子。例如,你的业务逻辑是从你

的数据库中获取一个用户列表。你的表现逻辑可能是把用户列表用3列显示。可

能修改用户列表函数使得它返回3个数组是很笨的办法。毕竟函数不应该关心数

据接下来要怎么处理这样的事情。然而,在你的模板文件中缺少一些逻辑,那些

正是你要做的事情。

在这点上Smarty是正确的(使得你利用PHP的很多东西),但是仍然有许多问题

。基本上,它仅仅提供了一个以新语法访问PHP的接口。以那开始,它看上去不

那么聪明了。是不是事实上写 {foreach --args} 比 <? foreach --args ?>; 更

加简单?如果你认为这样简单一些,问问你自己是不是在包含一个巨大的模板库

来到成这种分离时能够看到真正的意义要更加简单一些。诚然,Smarty提供了许

多其他很好的特性,但是看上去这些益处能够在不用承担包含Smarty类库的情况

下也能获得。



别样的解决方案
我主要要鼓吹的一个解决方案是一个使用PHP代码作为它的原生脚本语言的"模板

引擎"。我知道这以前有人做过。而且当我第一次看到的时候,我想,"为什么要

这样做?",然而我在考虑过我同事的论据之后,并且实现了一个直接使用PHP代

码仍然实现了把业务逻辑和表现逻辑分离的最终目标的模板系统时(只用了大约

25行代码,不包括注释),我意识到了好处所在。

这个系统给像我们这样的开发者提供了对PHP核心函数的访问权利,我们能够使

用他们来格式化输出——像日期格式化这样的任务应该在模板中处理。而且,因

为模板是普通的PHP文件,像Zend Performance Suite [6] 和PHP Accelerator

[7] 这样的字节码缓存程序,能够自动缓存模板(因而,它们不需要在每次被访

问时都被重新解释执行)。只要你记得把你的模板文件命名为程序能够辨认出是

PHP文件的名字(通常,你仅仅需要确保它们有一个.php的后缀),这确实是一

个好处。

当我认为这种方法比经典的模板引擎要高明得多时,肯定还有一些要商榷的问题

。最明显的反面意见是,PHP代码太复杂了,而且设计者不应该强迫去学习PHP。

事实上,PHP代码和像Smarty这样的高级模板引擎的语法差不多简单(如果不是

更简单的话)。而且,设计者能够使用像<?=$var;?>;这样的简写PHP。这要比

{$var}复杂很多?当然,这要长一些,但是如果你习惯了,你能够获得了PHP的

威力而且不用承受解析模板文件带来的负担。
第二,而且可能更重要的,在基于PHP的模板中没有固有的安全。Smarty提供了

选项在模板文件中彻底禁用PHP代码。它使得开发者能够约束模板能够访问的函

数和变量。如果你没有不怀好意的设计者,这不会是什么问题。然而,如果你允

许外部的用户上传或者修改模板,我在此展示的基于PHP的解决方案绝对没有任

何安全可言!任何代码都能放入模板中并且得到运行。是的,甚至是一个

print_r($GLOBALS)(这将改有恶意的用户访问脚本中任何变量的权利)。

但是,我个人或者工作上写过的项目中,绝大多数不允许最终的用户修改或者上

传模板。如果是这样,问题就不存在了。因此现在让我们来看看代码吧。



例子
这是一个简单的用户列表页面的例子。

[Copy to clipboard] [ - ]
CODE:
<?php  
require_once('template.php');  

/**  
* 这变量是保存模板文件的路径  
*/  
$path = './templates/';  

/**  
* 声明模板为对象 ,对类的使用。
*/  
$tpl = & new Template($path);  
$tpl->;set('title', 'User List');  

/**  
* 声明模板为对象 ,使用它的变量及函数。
* fetch_user_list() 函数传回数组.  
*/  
$body = & new Template($path);  
$body->;set('user_list', fetch_user_list());  

/**  
* 设置内部模板到 'body' 变量在
* 外部的模板  
*/  
$tpl->;set('body', $body->;fetch('user_list.tpl.php'));  

/**  
* 显示结果  
*/  
echo $tpl->;fetch('index.tpl.php');  
?>;

其中有两个值得注意的重要的概念。第一个就是内部和外部模板的概念。外部模

板包含定义站点主要外观的HTML代码。而内部模板包含定义站点内容区域的HTML

代码。当然,你能够在任意数目的层上有任意数目的模板。因为通常我们给每个

区域使用不同的模板对象,所以没有名字空间的问题。例如,我能在内部和外部

模板中都有变量叫"title",而不用害怕有什么冲突。

这是一个用来显示用户列表的模板的简单例子。注意特殊的foreach和

endforeach;语法在PHP手册中有说明 [8]。它完全是可选择的。

而且,你可能奇怪我为什么要用.php的后缀来命名我的模板文件。呵呵,许多

PHP字节码缓存解决方案(比如 phpAccelerator)如果要被认成PHP文件,需要

文件有一个.php后缀。因为这些模板是PHP文件,为什么不去获得这些好处?

[Copy to clipboard] [ - ]
CODE:
<table>;  
   <tr>;  
       <th>;Id</th>;  
       <th>;Name</th>;  
       <th>;Email</th>;  
       <th>;Banned</th>;  
   </tr>;  
<? foreach($user_list as $user): ?>;  
   <tr>;  
       <td align="center">;<?=$user['id'];?>;</td>;  
       <td>;<?=$user['name'];?>;</td>;  
       <td>;<a

href="mailto:<?=$user['email'];?>;">;<?=$user['email'];?>;</a>;</td>;  
       <td align="center">;<?=($user['banned'] ? 'X' :

'&');?>;</td>;  
   </tr>;  
<? endforeach; ?>;  
</table>;

这个layout.tpl.php是一个简单的例子(定义了整个页面看上去是什么样子的模

板文件)

[Copy to clipboard] [ - ]
CODE:
<html>;
   <head>;
       <title>;<?=$title;?>;</title>;
   </head>;

   <body>;

       <h2>;<?=$title;?>;</h2>;

<?=$body;?>;

   </body>;
</html>;

而这是解析后的输出。

[Copy to clipboard] [ - ]
CODE:
<html>;
<head>;
   <title>;User List</title>;
</head>;

<body>;

   <h2>;User List</h2>;

<table>;
<tr>;
   <th>;Id</th>;
   <th>;Name</th>;
   <th>;Email</th>;
   <th>;Banned</th>;
</tr>;
<tr>;
   <td align="center">;1</td>;
   <td>;bob</td>;
   <td>;<a href="mailto:[email protected]">;[email protected]</a>;</td>;
   <td align="center">;&</td>;
</tr>;
<tr>;
   <td align="center">;2</td>;
   <td>;judy</td>;
   <td>;<a href="mailto:[email protected]">;[email protected]</a>;</td>;
   <td align="center">;&</td>;
</tr>;
<tr>;
   <td align="center">;3</td>;
   <td>;joe</td>;
   <td>;<a href="mailto:[email protected]">;[email protected]</a>;</td>;
   <td align="center">;&</td>;
</tr>;
<tr>;
   <td align="center">;4</td>;
   <td>;billy</td>;
   <td>;<a href="mailto:[email protected]">;[email protected]</a>;</td>;
   <td align="center">;X</td>;
</tr>;
<tr>;
   <td align="center">;5</td>;
   <td>;eileen</td>;
   <td>;<a

href="mailto:[email protected]">;[email protected]</a>;</td>;
   <td align="center">;&</td>;
</tr>;
</table>;
</body>;
</html>;

缓存
因为解决方案简单如斯,实现模板缓存成为了一个非常简单的任务。为了实现缓

存,我们有一个二级类,它扩展了原来的模板类。CachedTemplate类事实上使用

和原来的模板类相同的API。不同点是我们必须传递缓存的设置给构造函数,并

且调用fetch_cache()而不是fetch()。

缓存的概念是简单的。简单的说,我们设置一个缓存时间来调表输出应该被保存

的时长(以秒为单位)。在产生一个页面的所有工作开展之前,我们必须首先测

试页面是否已经被缓存了,而且缓存是否仍然没有过期。如果缓存在这那,我们

不需要在去麻烦数据库和业务逻辑来产生页面——我们可以简单地输出原先缓存

地内容。

这种方法需要解决唯一地标识缓存文件的问题。如果一个站点是被一个显示基于

GET变量的中心脚本所控制,对每个PHP文件只有一个缓存不会有什么帮助。例如

,如果index.php?page=about_us和用户调用index.php?page=contact_us得到的

显示完全不同。

问题是通过给每个页面产生一个唯一的cache_id来解决的。为了做到这个目的,

我们把事实上被请求的文件变成REQUEST_URI(基本上就是整个URL:

index.php?foo=bar&bar=foo)。当然,这个转换过程是受到CachedTemplate类

控制的,但是要记住的重要的事情是你绝对要在创建CachedTemplate对象时传递

一个唯一的cache_id。当然下面有例子来说明。

使用缓存包括以下步骤。


include() 模板源文件


创建一个新的CachedTemplate对象(并且传递路径,唯一的cache_id和缓存过期

时间给模板)


测试内容是否已经被缓存了


如果还促拿了,显示文件并且结束脚本


否则,进行所有的处理并且fetch()模板


对fetch_cache()的调用将自动产生一个新的缓存文件

这个脚本假定你的缓存文件将放到./cache/中,因此你必须创建那个目录并且改

变它的目录权限(chmod)使得Web服务器能够写入文件。而且还要注意如果你在

编写脚本的过程中发现了错误,错误也会被缓存!因而在你开发的过程中禁用缓

存是一个好主意。最好的办法是给cache的生存周期传递0——这样,缓存总是立

即就失效了。

这是一个实际的缓存的例子。

[Copy to clipboard] [ - ]
CODE:
<?php
/**
* Example of cached template usage.  Doesn't provide any speed

increase since
* we're not getting information from multiple files or a database, but

it
* introduces how the is_cached() method works.
*/

/**
* First, include the template class.
*/
require_once('template.php');

/**
* Here is the path to the templates.
*/
$path = './templates/';

/**
* Define the template file we will be using for this page.
*/
$file = 'list.tpl.php';

/**
* Pass a unique string for the template we want to cache.  The

template
* file name + the server REQUEST_URI is a good choice because:
*    1. If you pass just the file name, re-used templates will all
*       get the same cache.  This is not the desired behavior.
*    2. If you just pass the REQUEST_URI, and if you are using

multiple
*       templates per page, the templates, even though they are

completely
*       different, will share a cache file (the cache file names are

based
*       on the passed-in cache_id.
*/
$cache_id = $file . $_SERVER['REQUEST_URI'];
$tpl = & new CachedTemplate($path, $cache_id, 900);
/**
* Test to see if the template has been cached.  If it has, we don't
* need to do any processing.  Thus, if you put a lot of db calls in
* here (or file reads, or anything processor/disk/db intensive), you
* will significantly cut the amount of time it takes for a page to
* process.
*
* This should be read aloud as "If NOT Is_Cached"
*/
if(!($tpl->;is_cached())) {
   $tpl->;set('title', 'My Title');
   $tpl->;set('intro', 'The intro paragraph.');
   $tpl->;set('list', array('cat', 'dog', 'mouse'));
}

/**
* Fetch the cached template.  It doesn't matter if is_cached()

succeeds
* or fails - fetch_cache() will fetch a cache if it exists, but if

not,
* it will parse and return the template as usual (and make a cache for
* next time).
*/
echo $tpl->;fetch_cache($file);
?>;

设置多个变量
我们如何能够同时设置多个变量?这又一个使用由Ricardo Garcia贡献的函数的

例子。

[Copy to clipboard] [ - ]
CODE:
<?php  
require_once('template.php');  

$tpl = & new Template('./templates/');  
$tpl->;set('title', 'User Profile');  

$profile = array(  
   'name' =>; 'Frank',  
   'email' =>; '[email protected]',  
   'password' =>; 'ultra_secret'  
);  

$tpl->;set_vars($profile);  

echo $tpl->;fetch('profile.tpl.php');  
?>;

相关的模板是这样的:

[Copy to clipboard] [ - ]
CODE:
<table cellpadding="3" border="0" cellspacing="1">;  
   <tr>;  
       <td>;Name</td>;  
       <td>;<?=$name;?>;</td>;  
   </tr>;  
   <tr>;  
       <td>;Email</td>;  
       <td>;<?=$email;?>;</td>;  
   </tr>;  
   <tr>;  
       <td>;Password</td>;  
       <td>;<?=$password;?>;</td>;  
   </tr>;  
</table>;

而且解析后的输出是这样的:

[Copy to clipboard] [ - ]
CODE:
<table cellpadding="3" border="0" cellspacing="1">;
<tr>;
   <td>;Name</td>;
   <td>;Frank</td>;
</tr>;
<tr>;
   <td>;Email</td>;
   <td>;[email protected]</td>;
</tr>;
<tr>;
   <td>;Password</td>;
   <td>;ultra_secret</td>;
</tr>;
</table>;

特别感谢Ricardo Garcia和Harry Fuecks他们的对这篇文章的贡献。



相关的链接
这儿是一个总体上探究模板引擎的好去处的列表。


Web Application Toolkit Template View [9] - 许多关于模板实现方法的信息
MVC Pattern [10] - 描述3层应用程序的设计
SimpleT [11] - 另一个使用PEAR::Cache_Lite的基于php的模板引擎
Templates and Template Engines [12] - 更多关于各种模板实现的信息
Smarty [13] - 编译型模板引擎



模板类源代码
以及最后出场的,模板类。

[Copy to clipboard] [ - ]
CODE:
<?php
/**
* Copyright (c) 2003 Brian E. Lozier ([email protected])
*
* set_vars() method contributed by Ricardo Garcia (Thanks!)
*
* Permission is hereby granted, free of charge, to any person

obtaining a copy
* of this software and associated documentation files (the

"Software"), to
* deal in the Software without restriction, including without

limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense,

and/or
* sell copies of the Software, and to permit persons to whom the

Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be

included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,

EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF

MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT

SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR

OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,

ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER

DEALINGS
* IN THE SOFTWARE.
*/

class Template {
   var $vars; /// Holds all the template variables
   var $path; /// Path to the templates

   /**
    * Constructor
    *
    * @param string $path the path to the templates
    *
    * @return void
    */
   function Template($path = null) {
       $this->;path = $path;
       $this->;vars = array();
   }

   /**
    * Set the path to the template files.
    *
    * @param string $path path to template files
    *
    * @return void
    */
   function set_path($path) {
       $this->;path = $path;
   }

   /**
    * Set a template variable.
    *
    * @param string $name name of the variable to set
    * @param mixed $value the value of the variable
    *
    * @return void
    */
   function set($name, $value) {
       $this->;vars[$name] = $value;
   }

   /**
    * Set a bunch of variables at once using an associative array.
    *
    * @param array $vars array of vars to set
    * @param bool $clear whether to completely overwrite the existing

vars
    *
    * @return void
    */
   function set_vars($vars, $clear = false) {
       if($clear) {
           $this->;vars = $vars;
       }
       else {
           if(is_array($vars)) $this->;vars = array_merge($this->;vars,

$vars);
       }
   }

   /**
    * Open, parse, and return the template file.
    *
    * @param string string the template file name
    *
    * @return string
    */
   function fetch($file) {
       extract($this->;vars);          // Extract the vars to local

namespace
       ob_start();                    // Start output buffering
       include($this->;path . $file);  // Include the file
       $contents = ob_get_contents(); // Get the contents of the

buffer
       ob_end_clean();                // End buffering and discard
       return $contents;              // Return the contents
   }
}

/**
* An extension to Template that provides automatic caching of
* template contents.
*/
class CachedTemplate extends Template {
   var $cache_id;
   var $expire;
   var $cached;

   /**
    * Constructor.
    *
    * @param string $path path to template files
    * @param string $cache_id unique cache identifier
    * @param int $expire number of seconds the cache will live
    *
    * @return void
    */
   function CachedTemplate($path, $cache_id = null, $expire = 900) {
       $this->;Template($path);
       $this->;cache_id = $cache_id ? 'cache/' . md5($cache_id) :

$cache_id;
       $this->;expire   = $expire;
   }

   /**
    * Test to see whether the currently loaded cache_id has a valid
    * corrosponding cache file.
    *
    * @return bool
    */
   function is_cached() {
       if($this->;cached) return true;

       // Passed a cache_id?
       if(!$this->;cache_id) return false;

       // Cache file exists?
       if(!file_exists($this->;cache_id)) return false;

       // Can get the time of the file?
       if(!($mtime = filemtime($this->;cache_id))) return false;

       // Cache expired?
       if(($mtime + $this->;expire) < time()) {
           @unlink($this->;cache_id);
           return false;
       }
       else {
           /**
            * Cache the results of this is_cached() call.  Why?  So
            * we don't have to double the overhead for each template.
            * If we didn't cache, it would be hitting the file system
            * twice as much (file_exists() & filemtime() [twice

each]).
            */
           $this->;cached = true;
           return true;
       }
   }

   /**
    * This function returns a cached copy of a template (if it

exists),
    * otherwise, it parses it as normal and caches the content.
    *
    * @param $file string the template file
    *
    * @return string
    */
   function fetch_cache($file) {
       if($this->;is_cached()) {
           $fp = @fopen($this->;cache_id, 'r');
           $contents = fread($fp, filesize($this->;cache_id));
           fclose($fp);
           return $contents;
       }
       else {
           $contents = $this->;fetch($file);

           // Write the cache
           if($fp = @fopen($this->;cache_id, 'w')) {
               fwrite($fp, $contents);
               fclose($fp);
           }
           else {
               die('Unable to write cache.');
           }

           return $contents;
       }
   }
}
?>;

另外一个值得注意的重要的事情是这里展示的解决办法是我们传递模板的文件名

给fetch()函数。如果你需要重用模板对象而不去re-set()所有的变量,这将比

较有用。

并且记住:模板引擎的要点是把你的业务逻辑从你的表现逻辑中分离出来,而不

是把你的PHP代码从HTML代码中分离出来。

本文附件下载:template.zip [1] http://www.massassi.com/bTemplate/
[2] http://smarty.php.net/
[3] http://www.sitepoint.com/examples/tempeng/template.zip
[4] http://opensource.org/licenses/mit-license.html
[5] http://www.opensource.org/
[6] http://zend.com/store/products/zend-performance-suite.php
[7] http://www.php-accelerator.co.uk/
[8] http://www.php.net/manual/en/con ... ernative-syntax.php
[9] http://wact.sourceforge.net/index.php/TemplateView
[10] http://www.phppatterns.com/index.php/article/articleview/11/
[11] http://simplet.sourceforge.net/
[12] http://phppatterns.com/index.php/article/articleview/4/1/1/
[13] http://smarty.php.net/

作者: cnw168   发布时间: 2004-06-11

要是不想学的人可以当我没发过。

作者: cnw168   发布时间: 2004-06-11

晕,这是exceed template 听说还不错

作者: magicianer   发布时间: 2004-06-11

呵呵,这个帖子居然贝翻出来了.
to 深空:
    我的想法是不想让模板文件带任何PHP的语句,而在生成的PHP文件中添加所需要的PHP语句,以便显示数据.这样也是为了便于修改.思路和你的模板有些不同.

to 财狼:
    咱俩想法差不多^_^.filemtime的效率在我现在论坛使用中是考虑进去的,后台设置有把此文件生成时间检测关闭的开关,它对效率确有影响,在论坛稳定运行之后九可以关闭它了.

to cnw168:
    单独运行可能有些问题,应为我贴出来的时候去掉了一些东西.
    我这个模板思想就是"简便","轻快",没有这些:"$tpl->;set('body', $body->;fetch('user_list.tpl.php')); "之类的东西,一个文件就是一个页面的完整模板,而不是把'user_list.tpl.php'单独分离出来.
    生成PHP文件后include即可,主要为了方便.

作者: lqpj   发布时间: 2004-06-11

热门下载

更多