Home  >  Article  >  Backend Development  >  [PHP] A simple and in-depth introduction to the template engine Smarty_PHP tutorial

[PHP] A simple and in-depth introduction to the template engine Smarty_PHP tutorial

WBOY
WBOYOriginal
2016-07-21 15:59:31848browse

Introduction to Smarty

What is a template engine

I don’t know since when, some people started to feel dissatisfied with embedding Server Script in HTML. However, whether it is Microsoft's ASP or open source PHP, they are all web server-side languages ​​with embedded Server Script. Therefore, some people think that it would be better if the program application logic (or business application logic) and the web page presentation (Layout) logic can be separated?
 
In fact, this problem has existed for a long time. When interactive web pages became popular, users of both ASP and PHP were both program developers and visual designers. But usually these users are either good at programming or good at art. If they want to take care of both at the same time, they will lose a lot of brain cells...
 
So the template engine came into being! The purpose of the template engine is to achieve the function of logical separation mentioned above. It allows program developers to focus on data control or function realization; while visual designers can focus on web page layout, making the web page look more professional! Therefore, the template engine is suitable for use by the company's website development team, allowing everyone to use their expertise!
 
As for the template engines that the author has come into contact with, they are roughly divided into two types according to the way the data is presented: template engines that need to be processed by programs and template engines that are completely determined by the template itself.
 
In a template engine that needs to be processed by a program, the program developer must be responsible for the presentation logic of the variables, which means that he must process the contents of the variables before outputting them to the template before he can do the assignment work. . In other words, program developers still have to write more programs to determine the appearance of variables. The template engine, which is completely determined by the template itself, allows variables to be assigned directly to the template, allowing the visual designer to decide how the variables are presented when designing the template. Therefore, it may have another set of its own template program syntax (such as Smarty) to facilitate the presentation of control variables. But in this way, visual designers also have to learn how to use template language.
 
The operating principle of the template engine. First, let's take a look at the following operation diagram:
 
General template engines (such as PHPLib) obtain the template to be parsed when creating a template object, and then After inserting the variables, parse the template through the parse() method, and finally output the web page.
 
For Smarty users, there is no need to do any parse actions in the program, Smarty will automatically do it for us. Moreover, if the template of a compiled web page has not changed, Smarty will automatically skip the compilation action and directly execute the compiled web page to save compilation time.
 
Using some concepts of Smarty
 
In general template engines, we often see the concept of regions. The so-called blocks will probably look like this:
 
Region content


Most of these blocks will be used in PHP programs with if or for, while To control their display status, although the template looks much simpler, as soon as the template is changed to a different display mode, the PHP program must be changed again!
 
In Smarty, everything is based on variables, and all presentation logic is controlled by the template. Because Smarty has its own template language, whether a block needs to be displayed or repeated, it is presented using Smarty's template syntax (if, foreach, section) and variable content. In this way, it feels like the template has become a bit complicated, but the advantage is that as long as you plan it properly, you don't have to change a single line of the PHP program.
 
From the above description, we can know that when using Smarty, we need to master one principle: clearly separate the program application logic and the web page rendering logic. That is to say, there should not be too much HTML code in the PHP program. In the program, you only need to decide which variables should be inserted into the template, and let the template decide how to present these variables (or even not appear at all).
 
 Basics of Smarty
 
 Installing Smarty
 
 First, we first decide where to place the program.
 
 Under Windows, there may be a location similar to this: "d:appservwebdemo".
 
 Under Linux, the location may be similar to this: "/home/jaceju/public_html/".
 
Go to Smarty’s official website to download the latest Smarty package: http://smarty.php.net.
 
After unlocking Smarty 2.6.0, you will see a lot of files, including the libs folder.在 libs 中应该会有 3 个 class.php 檔 + 1 个 debug.tpl + 1 个 plugin 资料夹 + 1 个 core 资料夹。然后直接将 libs 复制到您的程序主资料夹下,再更名为 class 就可以了。就这样?没错!这种安装法比较简单,适合一般没有自己主机的使用者。
  
  至于 Smarty 官方手册中为什么要介绍一些比较复杂的安装方式呢?基本上依照官方的方式安装,可以只在主机安装一次,然后提供给该主机下所有设计者开发不同程序时直接引用,而不会重复安装太多的 Smarty 复本。而笔者所提供的方式则是适合要把程序带过来移过去的程序开发者使用,这样不用烦恼主机有没有安装 Smarty 。
  
  程序的资料夹设定
  
  以笔者在Windows安装Appserv为例,程序的主资料夹是「d:\appserv\web\demo\」。安装好Smarty后,我们在主资料夹下再建立这样的资料夹:

  在 Linux 底下,请记得将 templates_c 的权限变更为 777 。Windows 下则将其只读取消。
  
  第一个用Smarty写的小程序
  
  我们先设定 Smarty 的路径,请将以下这个档案命名为 main.php ,并放置到主资料夹下:
  
  main.php:
  


  include "class/Smarty.class.php";
  define(@#__SITE_ROOT@#, @#d:/appserv/web/demo@#); // 最后没有斜线
  $tpl = new Smarty();
  $tpl->template_dir = __SITE_ROOT . "/templates/"; 
  $tpl->compile_dir = __SITE_ROOT . "/templates_c/"; 
  $tpl->config_dir = __SITE_ROOT . "/configs/"; 
  $tpl->cache_dir = __SITE_ROOT . "/cache/"; 
  $tpl->left_delimiter = @#<{@#;
  $tpl->right_delimiter = @#}>@#; 
  ?> 


照上面方式设定的用意在于,程序如果要移植到其它地方,只要改 __SITE_ROOT 就可以啦。 (这里是参考 XOOPS 的 )
  
  Smarty 的模版路径设定好后,程序会依照这个路径来抓所有模版的相对位置 (范例中是 @#d:/appserv/web/demo/templates/@# ) 。然后我们用 display() 这个 Smarty 方法来显示我们的模版。
  
  接下来我们在 templates 资料夹下放置一个 test.htm:(扩展名叫什么都无所谓,但便于视觉设计师开发,笔者都还是以 .htm 为主。)
  
  templates/test.htm:


   
   
   
  <{$title}> 
   
   
  <{$content}> 
   
   
   

  现在我们要将上面的模版显示出来,并将网页标题 ($title) 与内容 ($content) 更换,请将以下档案内容命名为 test.php ,并放置在主资料夹下:
  
  test.php:


  require "main.php";
  $tpl->assign("title", "测试用的网页标题"); 
  $tpl->assign("content", "测试用的网页内容"); 
  // 上面两行也可以用这行代替 
  // $tpl->assign(array("title" => "测试用的网页标题", "content" => "测试用的网页内容")); 
  $tpl->display(@#test.htm@#); 
  ?> 


请打开浏览器,输入 http://localhost/demo/test.php 试试看(依您的环境决定网址),应该会看到以下的画面:
   
 

  再到 templates_c 底下,我们会看到一个奇怪的资料夹 (%%179) ,再点选下去也是一个奇怪的资料夹 (%%1798044067) ,而其中有一个档案:
  
  templates_c/%%179/%%1798044067/test.htm.php:


 
   
   
   
  <?php echo $this->_tpl_vars[@#title@#]; ?\> 
   
   
  _tpl_vars[@#content@#]; ?\> 
   
   
   


 没错,这就是 Smarty 编译过的档案。它将我们在模版中的变量转换成了 PHP 的语法来执行,下次再读取同样的内容时, Smarty 就会直接抓取这个档案来执行了。
  
  最后我们整理一下整个 Smarty 程序撰写步骤:
  
  Step 1. 加载 Smarty 模版引擎。
  
  Step 2. 建立 Smarty 对象。
  
  Step 3. 设定 Smarty 对象的参数。
  
  Step 4. 在程序中处理变量后,再用 Smarty 的 assign 方法将变量置入模版里。
  
  Step 5. 利用 Smarty 的 display 方法将网页秀出。
  
  如何安排你的程序架构
  
  上面我们看到除了 Smarty 所需要的资料夹外 (class 、 configs 、 templates 、 templates_c) ,还有两个资料夹: includes 、 modules 。其实这是笔者模仿 XOOPS 的架构所建立出来的,因为 XOOPS 是笔者所接触到的程序中,少数使用 Smarty 模版引擎的架站程序。所谓西瓜偎大边,笔者这样的程序架构虽没有 XOOPS 的百分之一强,但至少给人看时还有 XOOPS 撑腰。
  
  includes 这个资料夹主要是用来放置一些 function 、 sql 檔,这样在 main.php 就可以将它们引入了,如下:
  
  main.php:
  



  include "class/Smarty.class.php";
  define(@#__SITE_ROOT@#, @#d:/appserv/web/demo@#); // 最后没有斜线
  // 以 main.php 的位置为基准
  require_once "includes/functions.php";
  require_once "includes/include.php";
  $tpl = new Smarty();
  $tpl->template_dir = __SITE_ROOT . "/templates/"; 
  $tpl->compile_dir = __SITE_ROOT . "/templates_c/"; 
  $tpl->config_dir = __SITE_ROOT . "/configs/"; 
  $tpl->cache_dir = __SITE_ROOT . "/cache/"; 
  $tpl->left_delimiter = @#<{@#;
  $tpl->right_delimiter = @#}>@#; 
  ?> 

 modules 这个资料夹则是用来放置程序模块的,如此一来便不会把程序丢得到处都是,整体架构一目了然。
  
  上面我们也提到 main.php ,这是整个程序的主要核心,不论是常数定义、外部程序加载、共享变量建立等,都是在这里开始的。所以之后的模块都只要将这个档案包含进来就可以啦。因此在程序流程规划期间,就必须好好构思 main.php 中应该要放那些东西;当然利用 include 或 require 指令,把每个环节清楚分离是再好不过了。
   
 

  在上节提到的 Smarty 程序 5 步骤, main.php 就会帮我们先将前 3 个步骤做好,后面的模块程序只要做后面两个步骤就可以了。
  
  从变量开始
  
  如何使用变量
  
  从上一章范例中,我们可以清楚地看到我们利用 <{ 及 }> 这两个标示符号将变量包起来。预设的标示符号为 { 及 } ,但为了中文冲码及 javascript 的关系,因此笔者还是模仿 XOOPS ,将标示符号换掉。变量的命名方式和 PHP 的变量命名方式是一模一样的,前面也有个 $ 字号 (这和一般的模版引擎不同)。标示符号就有点像是 PHP 中的
(事实上它们的确会被替换成这个) ,所以以下的模版变量写法都是可行的:
  
  1. <{$var}>
  
  2. <{ $var }> 
  
  3. <{$var
  
  }> 
  在 Smarty 里,变量预设是全域的,也就是说你只要指定一次就好了。指定两次以上的话,变量内容会以最后指定的为主。就算我们在主模版中加载了外部的子模版,子模版中同样的变量一样也会被替代,这样我们就不用再针对子模版再做一次解析的动作。
  
  而在 PHP 程序中,我们用 Smarty 的 assign 来将变量置放到模版中。 assign 的用法官方手册中已经写得很多了,用法就如同上一节的范例所示。不过在重复区块时,我们就必须将变量做一些手脚后,才能将变量 assign 到模版中,这在下一章再提。
  
  修饰你的变量
  
  上面我们提到 Smarty 变量呈现的风貌是由模版自行决定的,所以 Smarty 提供了许多修饰变量的函式。使用的方法如下:
  
  <{变量|修饰函式}> 
  
  <{变量|修饰函式:"参数(非必要,视函式而定)"}> 
  范例如下:
  
  <{$var|nl2br}> 
  
  <{$var|string_format:"%02d"}> 
  好,那为什么要让模版自行决定变量呈现的风貌?先看看底下的 HTML ,这是某个购物车结帐的部份画面。
  
  
  
  总金额:21,000 元
  一般模版引擎的模版可能会这样写:
  
  
  
  总金额:{format_total} 元
  它们的 PHP 程序中要这样写:


  $total = 21000;
  $tpl->assign("total", $total); 
  $tpl->assign("format_total", number_format($total)); 
  ?> 



而 Smarty 的模版就可以这样写: (number_format 修饰函式请到Smarty 官方网页下载)
  
  
  
  总金额:<{$total|number_format:""}> 元
  Smarty 的 PHP 程序中只要这样写:



  $total = 21000;
  $tpl->assign("total", $total); 
  ?> 


所以在 Smarty 中我们只要指定一次变量,剩下的交给模版自行决定即可。这样了解了吗?这就是让模版自行决定变量呈现风貌的好处!
  
  控制模版的内容
  
  重复的区块
  
  在 Smarty 样板中,我们要重复一个区块有两种方式: foreach 及 section 。而在程序中我们则要 assign 一个数组,这个数组中可以包含数组数组。就像下面这个例子:
  
  首先我们来看 PHP 程序是如何写的:
  
  test2.php:


  require "main.php";
  $array1 = array(1 => "苹果", 2 => "菠萝", 3 => "香蕉", 4 => "芭乐"); 
  $tpl->assign("array1", $array1); 
  $array2 = array( 
  array("index1" => "data1-1", "index2" => "data1-2", "index3" => "data1-3"), 
  array("index1" => "data2-1", "index2" => "data2-2", "index3" => "data2-3"), 
  array("index1" => "data3-1", "index2" => "data3-2", "index3" => "data3-3"), 
  array("index1" => "data4-1", "index2" => "data4-2", "index3" => "data4-3"), 
  array("index1" => "data5-1", "index2" => "data5-2", "index3" => "data5-3")); 
  $tpl->assign("array2", $array2); 
  $tpl->display("test2.htm"); 
  ?> 

而模版的写法如下:
  
  templates/test2.htm:



   
   
   
  测试重复区块 
   
   
  
  <br>  利用 foreach 来呈现 array1  <br>  <{foreach item=item1 from=$array1}>  <br>  <{$item1}>  <br>  <{/foreach}>  <br>  利用 section 来呈现 array1  <br>  <{section name=sec1 loop=$array1}>  <br>  <{$array1[sec1]}>  <br>  <{/section}>  <br>  利用 foreach 来呈现 array2  <br>  <{foreach item=index2 from=$array2}>  <br>  <{foreach key=key2 item=item2 from=$index2}>  <br>  <{$key2}>: <{$item2}>  <br>  <{/foreach}>  <br>  <{/foreach}>  <br>  利用 section 来呈现 array1  <br>  <{section name=sec2 loop=$array2}>  <br>  index1: <{$array2[sec2].index1}>  <br>  index2: <{$array2[sec2].index2}>  <br>  index3: <{$array2[sec2].index3}>  <br>  <{/section}>  <br>  
 
   
   
   

执行上例后,我们发现不管是 foreach 或 section 两个执行结果是一样的。那么两者到底有何不同呢?
  
  第一个差别很明显,就是foreach 要以巢状处理的方式来呈现我们所 assign 的两层数组变量,而 section 则以「主数组[循环名称].子数组索引」即可将整个数组呈现出来。由此可知, Smarty 在模版中的 foreach 和 PHP 中的 foreach 是一样的;而 section 则是 Smarty 为了处理如上列的数组变量所发展出来的叙述。当然 section 的功能还不只如此,除了下一节所谈到的巢状资料呈现外,官方手册中也提供了好几个 section 的应用范例。
  
  不过要注意的是,丢给 section 的数组索引必须是从 0 开始的正整数,即 0, 1, 2, 3, ...。如果您的数组索引不是从 0 开始的正整数,那么就得改用 foreach 来呈现您的资料。您可以参考官方讨论区中的此篇讨论,其中探讨了 section 和 foreach 的用法。
  
  巢状资料的呈现
  
  模版引擎里最令人伤脑筋的大概就是巢状资料的呈现吧,许多著名的模版引擎都会特意强调这点,不过这对 Smarty 来说却是小儿科。
  
  最常见到的巢状资料,就算论譠程序中的讨论主题区吧。假设要呈现的结果如下:
  
  公告区
  
  站务公告
  
  文学专区
  
  好书介绍
  
  奇文共赏
  
  计算机专区
  
  硬件外围
  
  软件讨论
  
  程序中我们先以静态资料为例:
  
  test3.php:


  require "main.php";
  $forum = array(
  array("category_id" => 1, "category_name" => "公告区", 
  "topic" => array( 
  array("topic_id" => 1, "topic_name" => "站务公告") 
  ) 
  ), 
  array("category_id" => 2, "category_name" => "文学专区", 
  "topic" => array( 
  array("topic_id" => 2, "topic_name" => "好书介绍"), 
  array("topic_id" => 3, "topic_name" => "奇文共赏") 
  ) 
  ), 
  array("category_id" => 3, "category_name" => "计算机专区", 
  "topic" => array( 
  array("topic_id" => 4, "topic_name" => "硬件外围"), 
  array("topic_id" => 5, "topic_name" => "软件讨论") 
  ) 
  ) 
  ); 
  $tpl->assign("forum", $forum); 
  $tpl->display("test3.htm"); 
  ?> 

模版的写法如下:
  
  templates/test3.htm:



   
   
  巢状循环测试 
   
   
   
  <{section name=sec1 loop=$forum}> 
   
   
   
  <{section name=sec2 loop=$forum[sec1].topic}> 
   
   
   
   
  <{/section}> 
  <{/section}> 
  
<{$forum[sec1].category_name}>
 <{$forum[sec1].topic[sec2].topic_name}>
 
   
   
   

执行的结果就像笔者举的例子一样。
  
  因此呢,在程序中我们只要想办法把所要重复值一层一层的塞到数组中,再利用 <{第一层数组[循环1].第二层数组[循环2].第三层数组[循环3]. ... .数组索引}> 这样的方式来显示每一个巢状循环中的值。至于用什么方法呢?下一节使用数据库时我们再提。
  
  转换数据库中的资料
  
  上面提到如何显示巢状循环,而实际上应用时我们的资料可能是从数据库中抓取出来的,所以我们就得想办法把数据库的资料变成上述的多重数组的形式。这里笔者用一个 DB 类别来抓取数据库中的资料,您可以自行用您喜欢的方法。
  
  我们只修改 PHP 程序,模版还是上面那个 (这就是模版引擎的好处~),其中 $db 这个对象假设已经在 main.php 中建立好了,而且抓出来的资料就是上面的例子。
  
  test3.php:
  


  require "main.php";
  // 先建立第一层数组
  $category = array();
  $db->setSQL($SQL1, @#CATEGORY@#); 
  if (!$db->query(@#CATEGORY@#)) die($db->error()); 
  // 抓取第一层循环的资料 
  while ($item_category = $db->fetchAssoc(@#CATEGORY@#)) 
  { 
  // 建立第二层数组 
  $topic = array(); 
  $db->setSQL(sprintf($SQL2, $item_category[@#category_id@#]), @#TOPIC@#); 
  if (!$db->query(@#TOPIC@#)) die($db->error()); 
  // 抓取第二层循环的资料 
  while ($item_topic = $db->fetchAssoc(@#TOPIC@#)) 
  { 
  // 把抓取的数据推入第二层数组中 
  array_push($topic, $item_topic); 
  } 
  // 把第二层数组指定为第一层数组所抓取的数据中的一个成员 
  $item_category[@#topic@#] = $topic; 
  // 把第一层数据推入第一层数组中 
  array_push($category, $item_category); 
  } 
  $tpl->assign("forum", $category); 
  $tpl->display("test3.htm"); 
  ?> 

在数据库抓取一笔资料后,我们得到的是一个包含该笔数据的数组。透过 while 叙述及 array_push 函式,我们将数据库中的资料一笔一笔塞到数组里。如果您只用到单层循环,就把第二层循环 (红色的部份) 去掉即可。
  
  决定内容是否显示
  
  要决定是否显示内容,我们可以使用 if 这个语法来做选择。例如如果使用者已经登入的话,我们的模版就可以这样写:
  
  <{if $is_login == true}>
  显示使用者操作选单
  <{else}>
  显示输入帐号和密码的窗体
  <{/if}>
  
  要注意的是,「==」号两边一定要各留至少一个空格符,否则 Smarty 会无法解析。
  
  if 语法一般的应用可以参照官方使用说明,所以笔者在这里就不详加介绍了。不过笔者发现了一个有趣的应用:常常会看到程序里要产生这样的一个表格: (数字代表的是资料集的顺序)
  
  1 2
  
  3 4
  
  5 6
  
  7 8
  
  这个笔者称之为「横向重复表格」。它的特色和传统的纵向重复不同,前几节我们看到的重复表格都是从上而下,一列只有一笔资料。而横向重复表格则可以横向地在一列中产生 n 笔资料后,再换下一列,直到整个循环结束。要达到这样的功能,最简单的方式只需要 section 和 if 搭配即可。
  
  我们来看看下面这个例子:
  
  test4.php:
  


  require "main.php";
  $my_array = array(
  array("value" => "0"), 
  array("value" => "1"), 
  array("value" => "2"), 
  array("value" => "3"), 
  array("value" => "4"), 
  array("value" => "5"), 
  array("value" => "6"), 
  array("value" => "7"), 
  array("value" => "8"), 
  array("value" => "9")); 
  $tpl->assign("my_array", $my_array); 
  $tpl->display(@#test4.htm@#); 
  ?> 


模版的写法如下:
  
  templates/test4.htm:


   
   
  横向重复表格测试 
   
   
   
   
  <{section name=sec1 loop=$my_array}> 
   
  <{if $smarty.section.sec1.rownum is div by 2}> 
   
   
  <{/if}> 
  <{/section}> 
   
  
<{$my_array[sec1].value}>
 
   
   
   

 重点在于 $smarty.section.sec1.rownum 这个 Smarty 变量,在 section 循环中这个变量会取得从 1 开始的索引值,所以当 rownum 能被 2 除尽时,就输出  使表格换列 (注意!是  在前面 在后面) 。因此数字 2 就是我们在一列中想要呈现的资料笔数。各位可以由此去变化其它不同的呈现方式。
  
  加载外部内容
  
  我们可以在模版内加载 PHP 程序代码或是另一个子模版,分别是使用 include_php 及 include 这两个 Smarty 模版语法; include_php 笔者较少用,使用方式可以查询官方手册,这里不再叙述。
  
  在使用 include 时,我们可以预先加载子模版,或是动态加载子模版。预先加载通常使用在有共同的文件标头及版权宣告;而动态加载则可以用在统一的框架页,而进一步达到如 Winamp 般可换 Skin 。当然这两种我们也可以混用,视状况而定。
  
  我们来看看下面这个例子:
  
  test5.php:


  require "main.php";
  $tpl->assign("title", "Include 测试"); 
  $tpl->assign("content", "这是模版 2 中的变量"); 
  $tpl->assign("dyn_page", "test5_3.htm"); 
  $tpl->display(@#test5_1.htm@#); 
  ?> 

模版 1 的写法如下:
  
  templates/test5_1.htm:


   
   
   
  <{$title}> 
   
   
  <{include file="test5_2.htm"}>
 
  <{include file=$dyn_page}> 
  <{include file="test5_4.htm" custom_var="自订变量的内容"}> 
   
   
   

模版 2 的写法如下:
  
  templates/test5_2.htm:
  
  <{$content}>
  模版 3 的写法如下:
  
  templates/test5_3.htm:
  
  这是模版 3 的内容
  模版 4 的写法如下:
  
  templates/test5_4.htm:
  
  <{$custom_var}>
  这里注意几个重点:1. 模版的位置都是以先前定义的 template_dir 为基准;2. 所有 include 进来的子模版中,其变量也会被解译。;3. include 中可以用「变量名称=变量内容」来指定引含进来的模版中所包含的变量,如同上面模版 4 的做法。
用PHP实现MVC开发模式的逻辑层和表示层有多种模板引擎可供选择,但是官方引擎SMARTY诞生后,选择就有了变化。它的理念和实现都是相当"前卫"的。本文主要讨论SMARTY之于其他模板引擎的不同特点,简要介绍了该引擎的安装及使用,并用一个小的测试案例对比了SMARTY和PHPLIB template的速度和易用性。

一、MVC需要模板

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

该图展示了一个简单的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!"




   
      $greetings
   
   
      $greetings
   


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


二、为什么选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默认目录结构来写应用的。这里需要手工指定,假设目录结构如下:
/uploadfiles/image008_67318.gif

就需要在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。别小看这称呼的不同,易用性标准分两块:模板文件和脚本文件的语法是否简明易用。

/uploadfiles/image010_85833.jpg

Let’s dive into the test. Let’s first look at the syntax of the two template files: the left side of the blue bar is the PHPLIB template, and the right side belongs to SMARTY. Personal preferences vary, so I won’t comment here. Focus on comparing the processing statements in the script, first look at the 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');

The following is SMARTY:

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

SMARTY only There are two variables, tags and row, while PHPLIB template has a handler for the template file and an inexplicable out. To be honest, I didn't know why this out existed when I first learned it. It still seems awkward now. Why does SMARTY have so few processing statements? The answer is that the work is done by the engine. If you like to delve into the source program, you can find that there is a function called _compile_tag() in Smarty_compiler.class.php, which is responsible for converting the section tag into a PHP statement. This is not an ordinary label. It has parameters and data, which saves the workload of script programming. The workload on the template label is not much different. It can be judged that SMARTY is higher in ease of use.

Now it’s our turn to focus on speed. After all, for a skilled web developer, it is only a matter of time to master the most difficult tool, not to mention the template engine, a technology with a flat learning curve. Speed ​​is the life of a web application, especially when the template engine is used on a site with a large number of concurrent visits, which is even more important. Before the test started, I thought PHPLIB template would win in this aspect because it has been upgraded many times and has basically no bugs. Moreover, SMARTY's engine is too big, unlike its opponent which only has two files.

Sure enough, the test results are as shown below, PHPLIB template has a 25% speed advantage:
/uploadfiles/image012_51369.gif

But it won’t always be like this. I pressed refresh again and got a different result this time:
/uploadfiles/image014_89692.gif

PHPLIB is basically unchanged, but SMARTY has increased the speed by 25%. Continue to refresh, and you will get results similar to the second time: SMARTY is nearly 10% faster than PHPLIB template. I think this is why the compiled version is faster than the interpreted version. The SMARTY engine itself is very large, and the template needs to be compiled into a php file, so the speed is certainly not as fast as the compact PHPLIB template. But this is only the case the first time. When receiving the request for the second time, SMARTY found that the template had already been compiled, so the most time-consuming step was skipped, and the opponent had to perform search and replacement step by step. This is a classic example of "exchanging space for time" mentioned in the principles of compilation.

5. Conclusion


The conclusion is that if you have fallen in love with SMARTY, then what are you waiting for? Of course, this does not mean that it is omnipotent. Just like when I use the MVC model to write my personal website, not only does it not reduce the workload, but I always have to worry about the coupling between different levels.

What is SMARTY not suitable for? Take a classic example from the manual: the weather forecast website. Another thing comes to mind: the stock market. Using SMARTY on this kind of website will be inefficient due to frequent recompilation, so PHPLIB template is more suitable.

This article is not to compare the two engines, but to illustrate the advantages of SMARTY. The most meaningful thing about using it is that it is part of the new PHP system. As an independent force, in addition to the two major systems of .NET and JAVA ONE, there are other options for large and medium-sized web development. For the GNU project, its significance is no different than Liu and Deng's army leaping thousands of miles into the Dabie Mountains.

www.bkjia.comtruehttp: //www.bkjia.com/PHPjc/317353.htmlTechArticleSmarty introduces what is a template engine. I don’t know since when, some people began to feel dissatisfied with embedding ServerScript in HTML. . However, whether it is Microsoft ASP or open source PHP,...
Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn