设为首页 收藏本站
查看: 530|回复: 0

[经验分享] PHP沉思录之三:Smarty

[复制链接]

尚未签到

发表于 2017-3-23 11:55:37 | 显示全部楼层 |阅读模式
在任何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的内容如下:
Html代码
     
  <?php  
  include_once("./smarty/Smarty.class.php");   
     
  $Smarty = new Smarty();   
  $Smarty->assign("HelloStr", "Hello, world");   
  $Smarty->display("TestSmarty.tpl");   
  ?>  

  
  <?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的内容如下:
  
Html代码
This is a string from Smarty: {$HelloStr}  

This is a string from Smarty: {$HelloStr}
  
   解析的结果为:
  
Html代码
This is a string from Smarty: Hello, world  

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方法之前):
  
Html代码
$Smarty->caching = 1;  

$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属性来设置生命期,代码如下:
  
Html代码
$Smarty->cache_lifetime = 1800;  

$Smarty->cache_lifetime = 1800;
  
        时间单位是秒,设置为1800表示当前缓存半小时后过期。
        Smarty还支持为同一个模板创建多个缓存实例,这在实际应用中是非常常见的。举例来说,假设某个博客系统中,显示article的页面为 Article.php,对应的模板文件为Article.tpl。但是,article页面的内容根据不同的article ID而不同,因此,必须为同一个页面创建不同的缓存实例。Smarty可以轻松做到这一点:
  
Html代码
$Smarty->display("Article.tpl", $ArticleId);  

$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,正在以稳健而持续的步伐,向企业级应用迈进。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-354126-1-1.html 上篇帖子: php 动态创建属性 下篇帖子: php header 404写法 php header函数用法
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表