PHP

每个进行过较大型的 PHP-Web
应用程序设计的开发人员大概都有如下的经历:花大量的时间写超文本语句,为页面排版,兼作美工等;或在整合的程序代码在和HTML静态页面时花费大量的时间。的确,用脚本语言开发
Web
应用不容易将数据的处理和数据的显示分开,但在多人合作的情况下,如果无法将数据和显示分开,将大大影响开发的效率,专业分工的发挥。为了解决这个问题,PHP
也提供了自己的解决方案,有多种,本文主要介绍 PHPLIB 中的 Template 类。

如果你正想知道什么是模板,首先去看一下Sascha
Schumann写的精彩文章《模板-为什么和如何在PHP3中使用它们(Templates – why
and how to use them in
PHP3)》的前几段。一般来说,模板可以让你完全地把你的PHP代码从HTML中分离出来,这样使得HTML的图形设计者们非常
高兴,而且可以避免他们搞丢你的宝贵设计。

在PHP世界中选择最合适的模板

一、模板处理类的设计

它不是FastTemplates
  那么,我们真的需要在PHPBuilder上关于模板的另一篇文章吗?好,是的,因为有不止一种的方法用PHP
来实现模板。Sascha的文章讲述了如何使用FastTEmplates,但是PHP基本类库(“PHPLIB”)有它自已的模板实
现。

事情的起因:你用过FastTemplate吗?对于PHP工程中的模板应用,其实我和我的同事们已经在许多的项目中接触过–关于它的好处,我想无论是在实际开发阶段还是上升到设计模式的角度都已经有很多”前辈先哲”讨论过了。就项目实施而言,在一些中型甚至大型的项目中,有效的将HTML和PHP代码分开,不仅在开发阶段可以分别提高界面设计人员和应用程序编写人员的工作效率,更会给项目的测试和维护带来巨大的便利。

模板处理类主要需完成以下的任务:

  它们有什么不同呢?FastTemplates最初是从一个Perl库转变来的。FastTemplates对Perl程序工作的很
好,但是对PHP不太理想。Kristian
Koehntopp从头编写了PHPLIB模板,作为一个纯的PHP库,它更好地提供
了PHP的优势。好处之一是Kristian的设计使用了preg_replace()来分析模板,据说比FastTemplate
中使用
的ereg_replace()要快。PHPLIB模板的另一个好处是它允许动态的块实现嵌套,不象FastTemplates。

但是–本文的目的不是讨论模板的优缺点,也不是作为指导性的教程讲授如何在PHP项目中使用模板,而是以应用的视角比较两种PHP世界中最为流行的模板处理方式:PHPLIB
Template和FastTemplate。

从模板文件中读取显示用的HTML代码。
将模板文件和实际生成的数据结合,生成输出的结果。 允许同时处理多个模板。
允许模板的嵌套。 允许对模板中的某个单独的部分进行处理。

  两个库都有着非常相似的特性和能力,但是如果你已经使用了FastTemplates,并且你想学习使用PHPLIB
模板,你应该把你所知道的关于FastTemplates
的一切都忘掉。他们的特性可能是相似的,但是PHPLIB模板
所做的每件事比FastTemplates只有一点点不同。

其实我一直都在”安静”的使用着PHPLIB
Template–很稳定而且看上去速度也不错,以至于我并不想再去不安的寻找可能更好的替代品–虽然我也知道这个地球上还有FastTemplate这样的东西。直到有一天,有一个同事问我:”不知道FastTemplate怎么样?为什么我们不试试FastTemplate呢?”

归纳上述任务,模板类的设计目标为:从多个模板文件中读入显示的HTML代码,将这些显示代码中需要动态数据的地方替换为PHP程序运算所得出的数据,然后按照一定的顺序输出。其中,替换的部分可以自由的设定。

使用PHPLIB模板
  让我们从一个简单的例子开始。我们假设在/home/mydir/mytemplates/下面有一个名为MyTemplate的模
板,它有一些文本,内容可能是:

“好吧,就让我们试试!”不过作为一个稳妥的方法,在任何新的模式或者方法引入项目之前,最好能够更加全面的了解它,以及找到一个或者几个足够说服自己和同事去采用它的理由–对于FastTemplate也不例外。

读取显示用的HTML代码采用读文件的方式

祝贺!你赢了一辆{some_color}Honda Prelude!

主角出场:了解PHPLIB
Template以及FastTemplate前面已经说过,我已经使用PHPLIB有一段时间了–我想屏幕前的你也许和我一样,也对这个优秀的工具类库印象很深吧!同样,当我开始寻求模板的解决办法时,很自然的就会在最接近身边的工具箱里搜寻,于是我找到了PHPLIB中的Template类。在最初的很快浏览完它提供的API之后,我就开始了使用它的历程–直到现在。

模板文件和数据的结合采用正则替换

  注意”{some_color}”是用大括号包围的。大括号指明some_color是一个模板变量。我们可能想写这样一
个脚本,它可以装入模板,在{some_color}模板变量的地方插入PHP变量$my_color的值,然后输出新的文本。
如果$my_color碰巧被设为”蓝色”,最后的输出可能是:

而FastTemplate似乎名气更响亮一些,在其发迹的Perl世界中自然是这样,在PHP世界中似乎也是,单单从这一点上就足够让人相信它的能力了。

处理多个模板用数组存储来实现。

祝贺!你赢了一辆新蓝色Honda Prelude!

关于两者的使用办法,本来我想在这里多废话几句的;但是毕竟觉得自己恐怕专门写出两篇教程来也没有现有的教程受欢迎–在本文的参考资料中有关于PHPLIB
Template和FastTemplate的有名教程,如果你自认还没有对这两种模板或者其中的一种有所认识,建议你先去看看那两篇文章,应该会得到不少有益的模板应用知识。

模板的嵌套的实现主要的想法是:将模板和输出一视同仁,都可拿来做替换,即可实现。

  下面是上述结果的PHP脚本:

(一番鼠标点击以及眼球转动甚至亲自编写测试代码之后,)现在你对两种模板都有了一些了解,也许已经发现了它们之间的很多相似之处,在下面我就会将这些地方归纳一下。

单独部分的处理的通过在模板文件中设定标注,然后在正则替换中结合标注来控制,实现部分替换。


变量的设置很明显,{FOO}或者{BAR}的形式在两种模板中都是指定的形式;也就是说,两种模板处理方式中,模板文件本身的外貌应该可以是一致的(比如都是HTML文件中间含有将要被替换的以{}标识的变量)。
模板类的初始化都需要在构建模板类的时候指定模板文件存在的目录位置。
变量的替换模板处理中最常用的就是变量替换,两种方式除了方法名不同之外(PHPLIB
Template采用set_var(),而FastTemplate采用assign,用法几乎也是一致的–可以采用的方式,也可以直接传递一个数组。
模板文件的处理都是采用为每一个模板文件指定一个句柄的办法,同时句柄也可以作为变量的值替换另一模板文件中的变量。
解析、输出过程都是需要调用parse将需要输出的模板文件解析后赋值给一个句柄,然后调用各自输出的方法,FastTemplate中是FastPrint输出该句柄的内容并结束处理。
重复解析的过程比如从数据库中取出几条记录需要显示而模板文件只有可替换的一行变量的时候,就很需要这样的功能。两者都具有这样的功能,只是使用时稍稍有些不同而已(PHPLIB
Template采用parse,而FastTemplate采用parse在值的前面多加一个点),应该说PHPLIB
Template的方法构造得相对优美一点。
区块解析的过程想像一下你需要从数据库中取出符合条件的数据并显示在网页中–但是因为条件会不尽相同,你并不能明确的知道会有多少条数据–这时候如果你又要采用模板,那么区块就是最好的选择。它是在模板中用特定的符号定义的部分,这一部分可以反复的被解析并添加到输出网页中。区块也许就像下面显示的一样(左边是PHPLIB
Template采用的区块设置,而右边则是FastTemplate采用的):

二、模板处理类的实现

<?php教程

好吧,如果你对以上苍白的文字介绍还是有些摸不着头脑,那么我们就来看看两个详尽的模板处理的例程吧!(如果你有兴趣对后面的测试代码进行发掘,就会发现其实以下的两个例子都来自那里)

请参看 PHPLib 中的 Template.inc,总共 345
行代码,有详细的注释。以下列举一些主要的函数,供研读参考:

include “template.inc”;

怎么样,是不是感觉几乎是一致的?下面是区块解析的例子,你也会发现同样的效果:

1) function set_file line 77, 读取文件

$my_color = “blue”;
// 将在后面使用

我们的测试目标和结果结束了对PHPLIB
Template和FastTemplate的了解,应该可以进入本文的正题了–在应用环境中当然应该选择易于使用同时速度理想的部件构建系统,那么对于这样的两种类似技术,进行评测非常有必要。评测应该是由两部分组成:技术的使用难度和速度的快慢程度–前者是评论的部分,而后者是测试的部分。对于前者,我们主要针对两个类提供的API进行评论;对于后者,我们会让测试的数据来说话,当然这中间免不了需要编写一些简单的测试代码。

2) function set_var($varname, $value = ) line 119,
设置映射数据-替换变量

$t = new Template(“/home/mydir/mytemplates/”);
// 创建一个名为 $t 的模板对象

回合一:技术的易用性这一回合主要是探讨PHPLIB
Template和FastTemplate提供的API的使用情况。应该说,前者提供的API更符合PHP的一些常见编码惯例(特别是当你的项目中采用了PHPLIB的其他类时,这样的规范性会对整个项目有好的影响);而后者的一些方法名总觉得有些别扭(希望你不要觉得这只是我的狭隘看法,比如FastPrint,同时方法的参数也不是非常”地道”,这一点你也可以从刚才的代码看出来。

3) function set_block($parent, $handle, $name = ) line 96, 设置标注

$t->set_file(“MyFileHandle”,”MyTemplate.ihtml”);
// 设置 MyFileHandle = 我们的模板文件

另外一点需要指出的是,对于模板区块的解析,FastTemplate直到最近的版本才开始支持。也就是说,如果你采用了之前的版本,在处理诸如数据库中记录的输出等内容时,不得不把这块内容独立存储在某处,然后在模板分析处理时附加上这个文件–真是一件让人难受的事情,尤其是对网页设计人员而言。

4) function subst($handle) line 136, 执行数据替换

$t->set_var(“some_color”,$my_color);
// 设置模板变量 some_color = $my_color值

当然还有一点需要考察–那就是对于PHP版本的支持。PHPLIB产生在PHP3的时代,这一点和FastTemplate差不多;但是根据我们的应用,PHPLIB在现在的PHP4环境下运行相当好,而FastTemplate的网页上则显示了一些信息表明对于PHP4也许它还有一些BUG存在。

5) function parse($target, $handle, $append = false) line 165,
执行模板文件与数据的结合

$t->parse(“MyOutput”,”MyFileHandle”);
// 设置模板变量 MyOutput = 分析后的文件

好了,讲了这么多(也许你会觉得都是FastTemplate的坏话),这个回合的胜利者很明显:PHPLIB
Template,尤其是你同时在使用PHPLIB的其他类时,这样的技术易用性更加明显(你将不会对这些出自同一个开发小组的API感到陌生)。

6) function p($varname) line 268, 输出处理结果

$t->p(“MyOutput”);
// 输出 MyOutput 的值(我们的分析后的数据)

回合二:处理速度也许这才是很多人最关注的部分–在这个回合中,我们会采用两种模板处理的方式:一种是常规的分析、替换,另一种是对区块的解析、替换–同时这样的两种方式也是在实际系统中应用最多的:前者是一般的页面处理,后者是关于数据库内容的输出处理。同时,由于两种模板类采用的模板文件的格式基本相同,使得我们可以提供几乎一致的模板文件分别供两种模板解析,更增加了测试的可信度。

注:本人下载的php-lib7.2c的Template.inc文件中的第95行少了个/,加上后使用正常。

?>——————————————————————————–
  第一行是一个include
指令,用来提供PHPLIB模板功能。当然PHPLIB做的比模板要多,但是如果你只想
使用模板特性,只需要包括tmplate.inc
(template.inc是来自于PHPLIB的文件之一)。PHPLIB模板使用面
向对象程序设计,所以下一件事情就是创建一个模板对象。代码 <? $t = new
Template (
“/home/mydir/mytemplates/” ); ?>
创建一个新的模板对象$t。这个$t对象是一个句柄,将用来处理
所有的模板函数,用于PHP脚本中其它的代码。如果你愿意,你可能创建其它的模板对象(每一个都有着自已
的模板变量名字空间),但是一个就够用了。在模板的构造函数调用中的路径(“/home/mydir/mytemplates/”)
用来设置你的模板所在位置的根目录,但是如果你没有设它,它将缺省与你的PHP脚本所在目录一样。

首先是确定测试的硬件和软件环境–硬件肯定是自己的机器了,Intel Celeron
733MHz, 256M RAM,40G HDD;软件平台中OS为Win2K
Pro,Web服务器为Apache+PHP,且以模块方式运行。

三、模板处理类的使用

  然后我们调用set_file()来定义一个名为”MyFileHandle”的句柄来与MyTemplate.ihtml链接(在parse()
被调用之前,模板不会真正地装入)。顺便说一下,PHPLIB模板的模板文件名的后缀为.ihtml
是一种习惯,
你可以使用.html,.tpl,或其它的后缀。然后调用set_var()来设置模板变量some_color为$my_color的值(
值为”蓝色”),意味着所有在模板中出现{some_color}的地方都将被词”蓝色”所替换,一旦我们调用了
parse()。

其次是规划这次测试的系统–当然先在Web服务器的文档根目录下开一个tpl_test的新目录用以放置这个测试的所有文件;然后在/tpl_test下建立include目录以存放两个模板类文件(我们测试的核心,以.inc.php为文件扩展名)以及一个测试类文件(包括了计时和记录日志以及读取日志并分析等功能,以.inc.php为文件扩展名)和一个数据文件(为区块解析的测试做准备,主要包含了一个二维数组,同样以.inc.php为文件扩展名),建立ihtml目录存放使用的模板文件(需要被解析的模板文件,以.ihtml为文件扩展名),建立logs目录存放测试产生的日志(后面就是发现,其实测试的数据就是由对这些日志的分析得到的,以.log为文件扩展名)。当然,两种模板的处理PHP文件就放在/test目录下。这次测试最关键的一点是,还需要建立一个PHP文件,对以上提到的负责模板处理的文件进行数次调用:比如一个文件fast_test.php是采用FastTemplate解析模板的,而phplib_test.php是采用PHPLIB
Template解析的,那么这个得出结果的PHP文件就负责多次以HTTP的方式请求以上的两个页面以获得测试数据。

3.1 最基本的例子

  接着我们调用parse(),它会装入MyFileHandle(MyTemplate.ihtml)进行分析,并且替换所有模板变量(“
{某变量}”)为模板变量的值,分析的结果放在MyOutput中。任何结果都不会输出到web服务器上,除非
p(“MyOutput”)被调用,它将输出最后分析过的文本。

选择待解析的模板和PHP程序编写–因为两种模板处理方式对于模板文件本身的格式要求几乎一致,因此可以尽量保证同一测试中两者选用的模板尽可能相同以谋求测试的最大公正性;同时在前文提到,为模拟现实系统中常用的两种模板应用:一般的页面处理和对数据库内容的输出处理,测试使用的模板文件也分成两种:一种是普通的带有一些待替换变量的模板文件,另一种是带有区块的需要根据应输出的内容反复替换的模板文件。同样对于这两种模板文件,也需要分别编写两种不同的PHP文件进行解析。

为了简单起见,这里假设模板文件、使用模板的PHP文件和模板处理类的文件都放在同一个目录下。PHPLIB中的习惯是使用ihtml后缀为模板文件的后缀。

 

测试方法–在浏览器中向/test/result.php提出请求,需要带参数type=[simple|complex],在返回的结果中即可看到两种模板在简单或者复杂模式下的测试结果。

下面是要使用的模板文件:

开展这样的速度测试之前会拟定一个测试方案,简单说来就是对于两种处理方式分别编写两个PHP测试页面,同时有一个控制测试的页面多次调用这两个页面并记录时间供采集测试数据。(如果有兴趣你还可以参考以下详细的测试方案,也许会对你深入了解这次测试有所帮助)

htmlheadtitle使用模板的测试/title/headbodyh2这是一个使用模板的测试文件!/h2当前的时间是{currenttime}!/body/html

小结–在整个测试系统完成之后,我们应该能够得到/test目录中如下的文件清单:

注:模板文件和通常的 HTML
文件差不多,唯一不同的是使用{}括起来的是可以被模板处理类替换的动态内容的变量。

Level 1Level 2Level
3Remark/test测试系统的根目录result.php进行测试并产生结果的PHP文件,测试时只需要在浏览器中请求该页面即可获得测试信息simple__test_phplib.php使用PHPLIB
Template对一般模板进行分析的PHP文件simple__test_fast.php使用FastTemplate对一般模板进行分析的PHP文件complex__test_phplib.php使用PHPLIB
Template对带区块模板进行分析的PHP文件complex__test_fast.php使用FastTemplate对带区块模板进行分析的PHP文件/include包含PHP类文件.inc.phpphplibTemplate.inc.phpPHPLIB
Template类文件FastTemplate.inc.phpFastTemplate类文件TplTest.inc.php测试中需要使用的测试类,包含诸如计时、读取/分析日志等方法。data.inc.php测试带区块模板时采用的数据文件。/ihtml包含模板文件.ihtmlsimple_phplib.ihtml采用PHPLIB
Template处理的一般模板文件simple_fast.ihtml采用FastTemplate处理的一般模板文件complex_phplib.ihtml采用PHPLIB
Template处理的带区块的模板文件complex_fast.ihtml采用FastTemplate处理的带区块的模板文件/logs包含日志文件.logsimple_phplib.log采用PHPLIB
Template处理一般模板生成的日志simple_fast.log采用FastTemplate处理一般模板生成的日志complex_phplib.log采用PHPLIB
Template处理带区块模板生成的日志complex_fast.log采用FastTemplate处理带区块模板生成的日志
12下一页阅读全文

接下来使用模板处理类来处理上面的模板:

?//引入Template类include(template.inc);//得到需要替换的数据$timeNow=date(Y-m-d H:i:s,time());//实例化一个Template类$template= new Template();//载入test.ihtml模板$template-set_file(handle1,test.ihtml);//使用$timeNow的值替换模板中的currenttime$template-set_var(currenttime,$timeNow);//进行实际的模板操作$template-parse(output,handle1);//输出最后结果$template-p(output);?

注:如果只想用PHPLIB中的模板类,只需在文件头包含Template.inc类即可。
创建Template对象时,可以指定模板文件路径,如:new
Template,缺省为当前路径。

3.2 模板嵌套与块设定

下面这个例子来自与PHPLIB的参考手册,综合性较强,这里需说明的一点是设定块的目的与嵌套无关,但这个范例包含了两者。请仔细阅读,块设定是为了避免这种情况:原本可在一个模板文件里完成的内容,因需要部分循环,而将部分循环内容提取单独做成模板文件。请思考,如果不用块设定,这个例子是不是需要3个模板文件呢?

模板文件1,page.ihtml

htmlheadtitle{PAGETITLE}/title/headbody bgcolor=#fffffftable border=1 cellpadding=4 cellspacing=0 bgcolor=#eeeeeetrtd colspan=2h1{PAGETITLE}/h1/td/trtrtd{OUT}/tdtdContent/td/tr/table/body/html

模板文件2,box.ihtml

!– start box.ihtml —

table border=1 bgcolor=#cccccc cellpadding=4 cellspacing=0trtd colspan=2b{TITLE}/b/td/tr!-- BEGIN row --trtd{NUM}/tdtd{BIGNUM}/tr!-- END row --/table!-- end box.ihtml --

模板处理文件,test.php

?php//引入Template类include(template.inc);#实例化一个Template类,名字叫$t$t = new Template();# 建立包含模板文件的数组$t-set_file(array(page = page.ihtml,box = box.ihtml));# 载入模板文件box中的一个块row,引用名称为rows$t-set_block(box, row, rows);# 设置替换$t-set_var(array(TITLE = Testpage,PAGETITLE = hugo));# 生成数据NUM,BIGNUMfor ($i=1; $i=3; $i++) { $n = $i; $nn = $i*10; #设置替换 $t-set_var(array(NUM = $n, BIGNUM = $nn)); #进行分析,分析的结果添加到rows的后面 $t-parse(rows, row, true);}# 生成box,再生成page$t-parse(OUT, array(box, page));# 输出最后结果$t-p(OUT);?
You can leave a response, or trackback from your own site.

Leave a Reply

网站地图xml地图