欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

PHP模板引擎SMARTY

程序员文章站 2022-05-27 10:50:18
用php实现mvc开发模式的逻辑层和表示层有多种模板引擎可供选择, 但是官方引擎smarty诞生后,选择就有...

用php实现mvc开发模式的逻辑层和表示层有多种模板引擎可供选择, 但是官方引擎smarty诞生后,选择就有了变化。它的理念和实现都是 相当"前卫"的。本文主要讨论smarty之于其他模板引擎的不同特点, 简要介绍了该引擎的安装及使用,并用一个小的测试案例对比了 smarty和phplib template的速度和易用性。

一、mvc需要模板
mvc最早是在smalltalk语言的开发过程中总结出的一种设计模式,mvc分别代 表了"模型"、"视图"和"控制",目的就是让不同的开发角色在大中型项目中各司 其职。在网络应用程序的开发中,可以用下图来表示各概念之间的关系。


该图展示了一个简单的web应用程序,用户在浏览器上看到信息是数据库服务 器上的内容,但在这之前经过了应用服务器加工。开发人员负责的就是建立数 据结构、处理数据的逻辑以及表示数据的方法。

96年cgi在中国开始流行的时候,早期的web程序员都是从html开始自学成材 的,在perl中print一行行的html并不是一件难事,但是随着网络的一步步提 速,页面大小也从当初的二、三十k暴涨了十倍。写cgi程序就产生了一个迫切 的要求:分开perl和html源码。于是,社会进步体现在开发小组内部的分工 上。由于美工和程序员对互相的工作并不是十分熟悉,在进行合作的过程中需 要用一种约定的"语言"进行交流。

这种语言并不是我们的母语或者英语,术语叫做"模板",逻辑和表示依靠它联 系。它是结合了html和脚本语言特征的一种表达方式。通过这种方式,表示层 可以按照用户所希望的格式来显示经过逻辑层处理过的数据。如果你有 windows平台下mfc的开发经验,那么一定会很熟悉document/document template/view的封装,这就是一个很典型的mvc例子。对于web应用来说,个 人认为j2ee中的ejb/servlets/jsp是最强大的,当然还有简洁优美的structs。 另一个很有名的实现就是com/dcom+asp,这个组合在我国是最多人使用 的。

通过几种mvc实现在web应用程序里的对比,可以得到一个关于模板的概念: 一组插入了html的脚本或者说是插入了脚本html,通过这种插入的内容来表 示变化的数据。下面给出一个模板文件的例子,这个模板经过处理后在浏览器 里显示"hello, world!"

引言:
--------------------------------------------------------------------------------


<html>
<head>
<title>$greetings</title>
</head>
<body>
$greetings
<body>
</html>


--------------------------------------------------------------------------------



这里暂且省略处理方式,在后面做专门对比讨论。

二、为什么选smarty?
对php来说,有很多模板引擎可供选择,比如最早的phplib template和后起之 秀fast template,经过数次升级,已经相当成熟稳定。如果你对目前手中的模 板引擎很满意,那么......也请往下看,相信你作为一个*软件爱好者或者追求 效率和优雅的开发者,下面的smarty介绍多少会有点意思。

除了个人偏好的影响,我一直倾向于使用官方标准的实现,比如apache的xml 引擎axis。好处就是可以获得尽可能好的兼容性(比如早期mfc对于win3x的兼 容性就比其它的应用程序框架好,当然现在各种版本都很完善了)。smarty发 布之前我一直使用的是pear 中的integrated template extension。这个引擎和 phplib template、fast template几乎是兼容的,从模板的语法到对模板的处理 同出一辙:都是将模板读入内存然后调用parse()函数,用数据对预置的标记进 行替换。

下面看看smarty是怎么做的。接到request后,先判断是否第一次请求该url, 如果是,将该url所需的模板文件"编译"成php脚本,然后redirect;如果不是, 就是说该url的模板已经被"编译"过了,检查不需要重编译后可以马上redirect, 重编译条件可以自己设定为固定时限,默认的是模板文件被修改。

怎么样,看起来是不是有点眼熟?想起来了──这不就是jsp的原理嘛!的确, 这种"编译"用在php这样的解释性脚本引擎上显得匪夷所思,但是仔细想 想,java不也是由jvm解释执行的吗?这就叫"没有做不到,只有想不到"。

既然谈到了java,就再对php的未来发表一点看法。php官方网站上宣布了要 在2003年年底发布php5.0版。这个版本拥有很多崭新的特性:比如异常处理, 命名空间,更加面向对象等等。可以说越来越向java靠拢,smarty也是新特 性之一,使得php更适用于大中型项目的开发。但是似乎离我当初选择它的原 因──灵巧易用──越来越远了。但就一个软件的生存周期来看,php正处在 成长期,开发者赋予它更多的功能,以期能胜任商业应用是利大于弊的。作为 php的忠实用户,肯定不希望php总是被人指责"能力不足"吧?

为什么选择smarty,仅仅因为它很像jsp?当然有更为充分的理由。首先,除 了第一次编译的成本比较高之外,只要不修改模板文件,编译好的cache脚本就 随时可用,省去了大量的parse()时间;其次smarty像php一样有丰富的函数 库,从统计字数到自动缩进、文字环绕以及正则表达式都可以直接使用;如果 觉得不够,比如需要数据结果集分页显示的功能,smarty还有很强的扩展能 力,可以通过插件的形式进行扩充。

事实胜于雄辩。我设计了一个测试程序,通过速度和开发难度这两个因素对比 了一下smarty和phplib template,选phplib template的原因是在patrick的 文章《在php世界中选择最合适的模板》中有一个phplib template对fast template 的竞赛,结果phplib template大获全胜,这使得smarty有了一个很好的对 手。在测试之前,先谈一下在安装过程中需要注意的问题。

三、可能遇到的问题
在smarty的官方网站上,有详尽的用户手册,可以选择在线html和pdf格式 的版本。这里就不再涉及手册上已有的内容,只是把初次使用可能遇到的问题 做个解释。

第一个问题就很要命:提示说找不到所需文件?并不是每一个人都按照 smarty默认目录结构来写应用的。这里需要手工指定,假设目录结构如下:


就需要在index.php里指定目录结构:
引言:
--------------------------------------------------------------------------------

$smart->template_dir = "smarty/templates/";
$smart->compile_dir = "smarty/templates_c/";
$smart->config_dir = "smarty/configs/";
$smart->cache_dir = "smarty/cache/";


--------------------------------------------------------------------------------



第一个问题解决了,紧接着就是第二个:我刚用dreamweaver生成的漂亮模板 怎么不能用?并不是模板文件有什么问题,而是因为smarty默认的标记分隔 符是{},不巧的是javascript肯定包含这个标记。好在我们可以用任意字符当作 分隔符,再加上这两句:
引言:
--------------------------------------------------------------------------------


$smart->left_delimiter = "{/";
$smart->right_delimiter = "/}";


--------------------------------------------------------------------------------



这下安装就基本完成,没问题了。

四、反衬和类比
先构思一下对测试的设计。主要的评比因素当然是速度了。为了进行速度测 试,采取了算术平均数的作法。在测试页面中重复将页面生成n遍,再对比总页 面生成时间。另一个重要因素是易用性(至于扩展性不用比较已经有结果了),所 以使用的模板不能太小。我用的是我个人主页的的页面,一个用 firework+dreamweaver生成的html文件,大小约7k。其中的变量设置也采取 最常用的区块,在phplib template里叫block,而smarty则称section。别小看 这称呼的不同,易用性标准分两块:模板文件和脚本文件的语法是否简明易 用。


下面就深入到测试中来。先看看两种模板文件的语法:蓝条左边是phplib template的模板,右边属于smarty。个人偏好是不一样的,所以这里不作评 论。着重对比一下脚本里的处理语句,先看phplib template的:
引言:
--------------------------------------------------------------------------------


$tpl->set_file('phplib', 'bigfile.htm');
$tpl->set_block('phplib', 'row', 'rows');
for ($j = 0; $j < 10; $j++){
$tpl->set_var('tag' ,"$j");
$tpl->parse('rows', 'row', true);
}
$tpl->parse('out', 'phplib');
$tpl->p('out');


--------------------------------------------------------------------------------


下面是smarty的:

引言:
--------------------------------------------------------------------------------

$smart->assign('row',$row);
$smart->display('bigfile.htm');

--------------------------------------------------------------------------------



smarty只用了tags和row两个变量,而phplib template则多了模板文件的 handler,还有一个莫名其妙的out。说实在的这个out我当初学的时候就不知道 为什么要存在,现在看起来,还是别扭。为什么smarty少那么多处理语句 呢?答案是工作由引擎完成了。如果你喜欢钻研源程序,可以发现在 smarty_compiler.class.php里有一个名叫_compile_tag()的函数,由它负责把 section这个标签转换成php语句。这不是一个普通的标签,它带有参数和数 据,节省了脚本编程的工作量,而模板标签上的工作量相差又不大,可以判定 在易用性上smarty高出一畴。

下面该轮到我们最关注的速度了,毕竟对于一个熟练的web开发者来说,掌握再 困难的工具不过是时间问题,何况模板引擎这种学习曲线平缓的技术。而速度 则是web应用程序的生命,尤其是模板引擎使用在并发访问量很大的站点上,这 点就更重要了。测试开始前,我觉得phplib template会在这一环节上胜出,因 为它经历了很多次升级,已经基本没有什么bug,而且smarty的引擎个头太 大,不像它的对手只有两个文件。

果然,测试结果如下图,phplib template有25%的速度优势:


但不会一直这样,我又按了一次刷新,这次得到了不一样的结果:


phplib基本没变化,但是smarty提高了25%的速度。继续刷新,得到的都是 类似于第二次的结果:smarty比phplib template 快上近10%。我想这就是编 译型比解释型快的原理了。smarty引擎本身就很大,加上还要把模板编译成 php文件,速度当然比不上小巧的phplib template。但这只是第一次的情况。 第二次接到请求的时候,smarty发现该模板已经被编译过了,于是最耗时的 一步被跳过了,而对手还要按部就班地进行查找和替换工作。这是编译原理里 讲到的很经典的"用空间换时间"例子。

五、结论
结论就是如果你已经爱上smarty了,那么还等什么呢?当然并不是说它就全 能,就如同我用mvc模式来写我的个人网站,非但没有减少工作量,反而总是 要为不同层次间的耦合劳神。

smarty不适合什么呢?举个手册里的经典例子:天气预报网站。我还想到一 个:股市大盘。在这种网站上用smarty会由于经常的重编译而效率偏低,还 是phplib template更为适合。

本文并不是为了对比两种引擎,而是为了说明smarty的优势。使用它最有意 义之处在于它是php新体系的一部份,作为一支独立的力量,除了.net和java one这两大体系之外,大中型web开发还有别的选择。这对于gnu项目来说, 其意义无异于刘邓大军千里跃进大别山。

参考文献

smarty官方站点:smarty.php.net
王晨:《在php世界中选择最合适的模板》
本文中测试程序下载:test.tar.bz2
http://phpe.net/uploads/attach/article_1058233528.bz2
about the author
于博翔,笔名于莱来自对外经济贸易大学信息学院。gnu痴迷者,喜欢练习各种编程语 言,研究各种体系框架。

发帖数:1275 回复:與許多的php script 都將使用smarty為核心引擎,而smarty到底是甚麼? 2003-08-10 14:07

在php世界中选择最合适的模板--比较phplib template和fasttemplate



php工程中的模板应用,是进行中型乃至大型项目中建议采用的处理表现层的好办法。但 是具体到模板的实施,采用何种现有的模板技术却需要进行一番比较。

php世界中比较受关注的模板处理有phplib template和fasttemplate两种,我们对技术的易用性和速 度进行了评测--想知道结果吗?

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

但是--本文的目的不是讨论模板的优缺点,也不是作为指导性的教程讲授如何在php项目中使用模板,而 是以应用的视角比较两种php世界中最为流行的模板处理方式(其实只不过是两种模板类):phplib template和fasttemplate。

其实我一直都在"安静"的使用着phplib template--很稳定而且看上去速度也不错,以至于我并不想再去 不安的寻找可能更好的替代品--虽然我也知道这个地球上还有fasttemplate这样的东西(而且还在perl的 世界中大名鼎鼎)。直到有一天,有一个同事问我:"不知道fasttemplate怎么样?为什么我们不试试 fasttemplate呢?"

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

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

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

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

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

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



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


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


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

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

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

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

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

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

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

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

(有点复杂的测试方案)

首先是确定测试的硬件和软件环境--硬件肯定是自己的机器了,intel celeron 733mhz, 256m ram,40g hdd;软件平台中os为win2k pro,web服务器为apache+php,且以 模块方式运行。

其次是规划这次测试的系统--当然先在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的方式请求以上的两个页面以获 得测试数据。

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

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

level 1
level 2
level 3
remark

/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.php



phplibtemplate.inc.php
phplib template类文件



fasttemplate.inc.php
fasttemplate类文件



tpltest.inc.php
测试中需要使用的测试类,包含诸如 计时、读取/分析日志等方法。



data.inc.php
测试带区块模板时采用的数据文件。







/ihtml

包含模板文件.ihtml



simple_phplib.ihtml
采用phplib template处理的一般模 板文件



simple_fast.ihtml
采用fasttemplate处理的一般模板文 件



complex_phplib.ihtml
采用phplib template处理的带区块 的模板文件



complex_fast.ihtml
采用fasttemplate处理的带区块的模 板文件







/logs

包含日志文件.log



simple_phplib.log
采用phplib template处理一般模板 生成的日志



simple_fast.log
采用fasttemplate处理一般模板生成 的日志



complex_phplib.log
采用phplib template处理带区块模 板生成的日志



complex_fast.log
采用fasttemplate处理带区块模板生 成的日志

经过了测试系统的设计和编写,并且向负责网页设计的同事讨来两个模板之后,我们就可以访问这个系统 了--前期的辛勤劳动使得现在观看结果的工作只需要在浏览器的地址栏中打入 http://localhost/tpl_test/ result.php?type=[simple|complex] (如果你是在其他的非本地服务器中进行这个测试,那么域名应采用 所在服务器的域名--比如我自己的机器叫做patrick等等)。下面是我自己在某一次的测试中获得的结 果:(测试结果数据解释)

名称
解释
备注

amount
测试总数(连续请求该页面总数)
该参数可在result.php文件中修改

max_seq
最大处理时间的序号
范围在1-amount之间

max_value
最大处理时间的值
峰值数据供参考

min_seq
最小处理时间的序号
范围在1-amount之间

min_value
最小处理时间的值
峰值数据供参考

average
平均处理时间
测试中最有价值的数据


当然,如果你觉得一次测试的结果并不可靠,可以反复按下浏览器的刷新按钮,就能够观察到不同测试的

结果(理论上应该是相差无几)。

测试结果以及颁发"xx选择奖"
好了,在偏重速度测试的回合二中phplib template以惊人的2倍的速度战胜了fasttemplate;而同时在 第一回合中phplib template有以良好的api设计和易用性占得上风。结果显而易见--我们的选择奖当然颁 发给了phplib template,同时这次的测试也让我们对phplib这个类库设计有了更深的了解。

主观评价
既然有了结果,那么fasttemplate自然也就不能进入我们的项目了--虽然从结果上看来我们花费了半天的 时间得到了一个毫无变化的结果(phplib template继续很好的在项目中使用),但是测试的过程却是很 有价值的,特别是采用php进行测试的方法,应该会在以后的类似决策中起到一定参考作用。