﻿<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Gavin&#039;s Blog &#187; Smarty</title>
	<atom:link href="http://laigw.name/tag/smarty/feed" rel="self" type="application/rss+xml" />
	<link>http://laigw.name</link>
	<description>Keep it simple, stupid. Simplicity is beauty.</description>
	<lastBuildDate>Sun, 29 Jan 2012 07:14:51 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>PHP沉思录之三：Smarty</title>
		<link>http://laigw.name/post/189.html</link>
		<comments>http://laigw.name/post/189.html#comments</comments>
		<pubDate>Tue, 18 Nov 2008 09:34:37 +0000</pubDate>
		<dc:creator>Gavin</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Smarty]]></category>
		<category><![CDATA[沉思录]]></category>

		<guid isPermaLink="false">http://www.laigw.name/?p=189</guid>
		<description><![CDATA[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。
但是，模板技术也有其先天的缺陷：
	1、无法彻底分离逻辑。显示逻辑和HTML代码很难通过简单的标签替换，实现彻底的分离。例如，遍历并显示一个数组，在PHP中可以用简单的foreach语句实现，但是使用模板时，就需要进行对整个模板文件进行多次替换操作，造成效率的极大降低；或者根据不同的数据值显示不同的格式，如果模板文件完全不包含PHP代码，那么将很难做到这一点。
	2、解析导致的性能损失。由于每次PHP页面被访问时，解析器都必须对模板文件进行替换操作，无疑会降低PHP应用的性能。尤其在多次的替换操作时更是如此。因此，不使用模板比使用模板往往更加快速，这也是许多PHP程序员摒弃模板技术的原因之一。 
    在经过数年的发展之后，“编译型”的模板技术渐渐占据了主流。所谓“编译型”，是指解析器读取模板文件以后，并不直接生成静态HTML，而是“编译”成一个新的PHP文件，并将它保存起来。以后访问该页面时，模板引擎会直接执行“编译”后的PHP文件。Smarty是这种模板引擎的代表。
针对以上的两个问题，Smarty作了如下处理： 
	1、独立语法。Smarty实现了一套自己的语法，这套语法不但支持变量替换和简单的判断，而且支持循环，修饰符（modifier），内置了很多功能强大的函数，而且还支持自定义函数。这套系统保证Smarty能够完全独立地处理显示输出，无须再和PHP有什么瓜葛。事实上，在Smarty模板中，是不可以直接使用PHP代码的（通过显式定义可以使用），这也是一种强制分离逻辑层和表现层的方式。(理论上来说，Smarty的模板文件也可以应用于其它语言。)但是，这种解决方式也受到了指责，因为Smarty的语法过于强大，几乎变成了一门新的语言，指责者认为，这反而增加了复杂性。但是，根据作者的实际经验，Smarty的语法不但非常简单直观，而且只需要掌握一些最初级的语法，就足可以应付绝大多数的应用。即使是不懂编程的网页设计师，也很容易就能够掌握。
	2、编译机制。Smarty的“编译”机制，节省了用于反复解析模板文件的时间，极大地提高了速度。由于“编译”后生成的是标准的PHP文件，因此从理论上来说，执行的速度不会低于没有模板的PHP应用的速度。在一些和解析型模板引擎进行的对比测试中，Smarty在第一次访问时落后，但是在以后的访问中速度远远超出竞争对手。而且，这种编译过程是智能的，在模板文件的内容被改变后，Smarty会自动重新编译，因此对于开发者来说，编译过程完全无需人工干预。另外，如果你愿意的话，生成的PHP文件还可以方便地应用于Zend Accelerator这样的工具，进行二次编译。 
除此之外，Smarty还拥有其他一些优秀的特性： 
	1、缓存机制。由于实现了编译机制，在接收到对某个模板文件的访问请求时，Smarty会自动将它重定向到编译后的PHP文件。但是，这也意味着，Smarty也可以将它重定向到任何其他的文件——例如静态的HTML文件。在此基础之上，Smarty实现了自己的基于页面的缓存机制。Smarty能够将编译后的PHP文件产生的结果——静态HTML——保存起来，将重复发送的请求直接重定向给它，这意味着对于第一次之后的请求，不需要执行任何PHP代码（Smarty本身的代码当然除外）。对于不需要频繁更新的页面（我们知道这种网页往往在整个网站中占大多数），通过这种缓存机制获取的性能提升是惊人的。而且，由于它是在页面级实现的，因此完全无须涉及到复杂的对象级缓存问题，保持了逻辑上的简单性。
	2、可配置性。Smarty在开发之初就将高度的可配置性作为自己的一个设计目标。它本身以100%的PHP编写，以源代码的方式发行，只需要将Smarty简单地拷贝到你的文件路径中，就可以使用了。Smarty的各项配置变量，都可以通过修改config文件或者手动编码进行定制。例如，Smarty默认的定界符是花括号（{}），但是这往往和Javascript以及CSS中的花括号冲突。为了解决这一问题，可以简单地将默认定界符修改为其他的字符（例如ASP风格的“”）。
	3、可扩展性。Smart的实现基于面向对象的架构，并且提供了插件机制，非常便于用户修改和扩展其默认的认为。当然，你也可以直接修改它的源代码来达到目的。（对于基于脚本语言的开源应用来说，这是非常惬意的，因为你甚至不需要重新编译。） 
让我们来看一个最简单的Smarty应用。这个应用包括两个文件：
	TestSmarty.php 调用Smarty类库，初始化变量，并解析相应的模板文件
	TestSmarty.tpl 模板文件，其实就是包含了Smarty标签的HTML，放在指定的模板目录下，默认是./templates
　　
	TestSmarty.php的内容如下：

&#160;查看代码 PHP1
2
3
4
5
6
	&#60;?php 
	include_once&#40;&#34;./smarty/Smarty.class.php&#34;&#41;; 
	$Smarty = new Smarty&#40;&#41;; 
	$Smarty-&#62;assign&#40;&#34;HelloStr&#34;, &#34;Hello, world&#34;&#41;; 
	$Smarty-&#62;display&#40;&#34;TestSmarty.tpl&#34;&#41;; 
	?&#62;

这个文件的内容非常简单，任何有过PHP经验的程序员都应该能够理解：首先将Smarty类库所在的文件include进来，然后创建一个新的Smarty对象，并对HelloStr变量进行赋值，最后解析TestSmarty.tpl文件。
	TestSmarty.php的内容如下：

&#160;查看代码 PHP1
2
　　 
	This is a string from Smarty: &#123;$HelloStr&#125;

　　 
解析的结果为：
　

&#160;查看代码 PHP1
2
　 
	This is a string from Smarty: Hello, world

此时检查存放编译后的PHP文件的子目录（默认是./templates_c）,可以找到一个名叫%%65^650^65099D8B%%TestSmarty.tpl.php的文件，内容如下：
　

&#160;查看代码 PHP1
2
3
4
　 
	&#60;?php [...]]]></description>
		<wfw:commentRss>http://laigw.name/post/189.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

