PHP沉思录-第三篇-Smarty-左轻侯-《程序员》2007年10月号

建立时间:2007-10-31 21:23:11   最后修改时间:2007-10-31 21:23:11  
php

PHP沉思录之三:Smarty 
  左轻侯 
  2007.8.11 
   
   在任何Web应用中,如何将程序代码和界面设计,或者说,将逻辑层和表现层分离开来,都会是一个问题。对于PHP这种类型的嵌入网页的脚本语言,这一问题尤为突出。在新手编写的代码中,把访问数据库的代码和操纵HTML元素的代码写在同一个页面里,是很常见的状况。为了不这一问题,开发者倾向于将涉及业务逻辑的代码封装在某些单独的库文件中,再在负责显示界面的文件中将它们include进来。可是,这仍然没法避免在显示界面的文件中包含大量的PHP代码。究其因此然,是由于除了涉及业务逻辑的代码之外,即便仅仅在显示层,也每每涉及到复杂的显示逻辑。在一个典型的显示页面中,程序须要先包含全部必需的库文件,初始化上下文环境,建立相关业务逻辑对象(假如数据库访问代码已经被业务逻辑对象封装,能够节省数据库相关的代码),最后在HTML的空隙中把对象格式化为HTML元素进行显示。因而咱们看到了无数这样的页面,在第一行HTML开始以前,就已经包含了数十行甚至更多的PHP代码,在HTML的内部,仍然充满了各类各样的PHP代码。所以,PHP代码和HTML代码搅和在一块的问题仍然没法解决,对HTML的修改仍然可能致使整个PHP程序崩溃。更加麻烦的是,这种不清晰的结构妨碍了PHP应用在规模上的进一步扩张。 
   为了解决这一问题,模板(template)技术应运而生。模板技术的基本原理是,经过一个解析器(parser),读取指定的模板文件(包含了某些特定标签的HTML文件),将这些标签替换为相关的PHP变量,再输出为标准的HTML。经过这种方式,不但分离了业务逻辑层和表现层,并且也尽量地分离了显示逻辑和HTML代码。经过替换不一样的模板文件,能够方便地生成各类格式的输出,例如HTML,XML,WML,后期稍加处理甚至能够生成PDF和Flash。早期较为著名的PHP模板引擎有PHPLib中的Template和FastTemplate。 
   可是,模板技术也有其先天的缺陷。 
   
   没法完全分离逻辑。显示逻辑和HTML代码很难经过简单的标签替换,实现完全的分离。例如,遍历并显示一个数组,在PHP中能够用简单的foreach语句实现,可是使用模板时,就须要进行对整个模板文件进行屡次替换操做,形成效率的极大下降;或者根据不一样的数据值显示不一样的格式,若是模板文件彻底不包含PHP代码,那么将很难作到这一点。 
   解析致使的性能损失。因为每次PHP页面被访问时,解析器都必须对模板文件进行替换操做,无疑会下降PHP应用的性能。尤为在屡次的替换操做时更是如此。所以,不使用模板比使用模板每每更加快速,这也是许多PHP程序员摒弃模板技术的缘由之一。 
   
  在通过数年的发展以后,“编译型”的模板技术渐渐占据了主流。所谓“编译型”,是指解析器读取模板文件之后,并不直接生成静态HTML,而是“编译”成一个新的PHP文件,并将它保存起来。之后访问该页面时,模板引擎会直接执行“编译”后的PHP文件。Smarty是这种模板引擎的表明。 
   针对以上的两个问题,Smarty做了以下处理: 
   
   独立语法。Smarty实现了一套本身的语法,这套语法不但支持变量替换和简单的判断,并且支持循环,修饰符(modifier),内置了不少功能强大的函数,并且还支持自定义函数。这套系统保证Smarty可以彻底独立地处理显示输出,无须再和PHP有什么瓜葛。事实上,在Smarty模板中,是不能够直接使用PHP代码的(经过显式定义可使用),这也是一种强制分离逻辑层和表现层的方式。(理论上来讲,Smarty的模板文件也能够应用于其它语言。)可是,这种解决方式也受到了指责,由于Smarty的语法过于强大,几乎变成了一门新的语言,指责者认为,这反而增长了复杂性。可是,根据做者的实际经验,Smarty的语法不但很是简单直观,并且只须要掌握一些最初级的语法,就足能够应付绝大多数的应用。即便是不懂编程的网页设计师,也很容易就可以掌握。 
   编译机制。Smarty的“编译”机制,节省了用于反复解析模板文件的时间,极大地提升了速度。因为“编译”后生成的是标准的PHP文件,所以从理论上来讲,执行的速度不会低于没有模板的PHP应用的速度。在一些和解析型模板引擎进行的对比测试中,Smarty在第一次访问时落后,可是在之后的访问中速度远远超出竞争对手。并且,这种编译过程是智能的,在模板文件的内容被改变后,Smarty会自动从新编译,所以对于开发者来讲,编译过程彻底无需人工干预。另外,若是你愿意的话,生成的PHP文件还能够方便地应用于Zend Accelerator这样的工具,进行二次编译。 
   
  除此以外,Smarty还拥有其余一些优秀的特性: 
   
   缓存机制。因为实现了编译机制,在接收到对某个模板文件的访问请求时,Smarty会自动将它重定向到编译后的PHP文件。可是,这也意味着,Smarty也能够将它重定向到任何其余的文件——例如静态的HTML文件。在此基础之上,Smarty实现了本身的基于页面的缓存机制。Smarty可以将编译后的PHP文件产生的结果——静态HTML——保存起来,将重复发送的请求直接重定向给它,这意味着对于第一次以后的请求,不须要执行任何PHP代码(Smarty自己的代码固然除外)。对于不须要频繁更新的页面(咱们知道这种网页每每在整个网站中占大多数),经过这种缓存机制获取的性能提高是惊人的。并且,因为它是在页面级实现的,所以彻底无须涉及到复杂的对象级缓存问题,保持了逻辑上的简单性。 
   可配置性。Smarty在开发之初就将高度的可配置性做为本身的一个设计目标。它自己以100%的PHP编写,以源代码的方式发行,只须要将Smarty简单地拷贝到你的文件路径中,就可使用了。Smarty的各项配置变量,均可以经过修改config文件或者手动编码进行定制。例如,Smarty默认的定界符是花括号({}),可是这每每和Javascript以及CSS中的花括号冲突。为了解决这一问题,能够简单地将默认定界符修改成其余的字符(例如ASP风格的“<%”和“%>”)。 
   可扩展性。Smart的实现基于面向对象的架构,而且提供了插件机制,很是便于用户修改和扩展其默认的认为。固然,你也能够直接修改它的源代码来达到目的。(对于基于脚本语言的开源应用来讲,这是很是惬意的,由于你甚至不须要从新编译。) 
   
  让咱们来看一个最简单的Smarty应用。这个应用包括两个文件: 
   
  TestSmarty.php 调用Smarty类库,初始化变量,并解析相应的模板文件 
  TestSmarty.tpl 模板文件,其实就是包含了Smarty标签的HTML,放在指定的模板目录下,默认是./templates 
   
   TestSmarty.php的内容以下: 
   
  <?php 
  include_once("./smarty/Smarty.class.php"); 
   
  $Smarty = new Smarty(); 
  $Smarty->assign("HelloStr", "Hello, world"); 
  $Smarty->display("TestSmarty.tpl"); 
  ?> 
   
   这个文件的内容很是简单,任何有过PHP经验的程序员都应该可以理解:首先将Smarty类库所在的文件include进来,而后建立一个新的Smarty对象,并对HelloStr变量进行赋值,最后解析TestSmarty.tpl文件。 
   TestSmarty.php的内容以下: 
   
  This is a string from Smarty: {$HelloStr} 
   
   解析的结果为: 
   
  This is a string from Smarty: Hello, world 
   
   此时检查存放编译后的PHP文件的子目录(默认是./templates_c),能够找到一个名叫%%65^650^65099D8B%%TestSmarty.tpl.php的文件,内容以下: 
   
  <?php /* Smarty version 2.6.18, created on 2007-08-12 03:04:56 
   compiled from TestSmarty.tpl */ ?> 
  This is a string from Smarty: <?php echo $this->_tpl_vars['HelloStr']; ?> 
   
   这就是Smarty引擎编译生成的结果。 
   为了启用缓存,能够在TestSmarty.php文件中加入这么一行(固然必须在display方法以前): 
   
  $Smarty->caching = 1; 
   
   从新访问该页面,而后检查存放缓存文件的子目录(默认是./cache),能够找到一个名叫%%65^650^65099D8B%%TestSmarty.tpl的文件,内容以下: 
   
  136 
  a:4:{s:8:"template";a:1:{s:14:"TestSmarty.tpl";b:1;}s:9:"timestamp";i:1186888266;s:7:"expires";i:1186891866;s:13:"cache_serials";a:0:{}}This is a string from Smarty: Hello, world 
   
   这就是生成的缓存文件,在静态的HTML文件以前,包含了已经序列化的PHP信息。虽然这些信息没法被直接阅读,可是多少仍是可以猜想出来:模板的子目录,模板文件名,时间戳,生存期(过时时间),等等。若是读者有兴趣研究它们的详细定义,能够阅读Smarty的源代码。 
   注意,上述信息中包含了一项:生存期,即当前缓存在多长时间之后过时。Smarty默认的生存期是1小时,即3600秒。能够经过修改Smarty属性来设置生命期,代码以下: 
   
  $Smarty->cache_lifetime = 1800; 
   
   时间单位是秒,设置为1800表示当前缓存半小时后过时。 
   Smarty还支持为同一个模板建立多个缓存实例,这在实际应用中是很是常见的。举例来讲,假设某个博客系统中,显示article的页面为Article.php,对应的模板文件为Article.tpl。可是,article页面的内容根据不一样的article ID而不一样,所以,必须为同一个页面建立不一样的缓存实例。Smarty能够轻松作到这一点: 
   
  $Smarty->display("Article.tpl", $ArticleId); 
   
   只要将一个惟一标识符(在这个例子中是article的ID)做为第二个参数传给display方法,Smarty就会自动完成一切。 
   
   Smarty出现的时间虽然较老牌的PHPLib Template和FastTemplate为晚,可是发展很是迅速,并且已经成为PHP的官方子项目,拥有二级域名http://smarty.php.net/。正如它的官方站点上所说,与其说Smarty是一个模板引擎,不如说它是一个表现层的Framework。这句话极为重要。
   做者我的认为,Smarty诞生和逐渐取得主流地位的意义,不只仅是提供了一个优秀的模板引擎,而是表示PHP在解决更大规模的应用上迈出了坚实的一步。若是说Java是一开始就将解决大规模应用做为本身的设计目标的话,那么PHP就是在开源社区的推进下,在不断的改进中逐渐接近这一目标。当一个PHP应用采用了Smarty这样优秀和成熟的表现层解决方案,以及其余一些相似的技术(例如好的ORM解决方案)之后,它可以解决的问题的规模就比过去大得多了。经过这些现象,咱们能够看到,PHP,或者说LAMP,正在以稳健而持续的步伐,向企业级应用迈进。 程序员

相关文章
相关标签/搜索