💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
我们将对比使用smarty模板引擎和没使用smarty模板引擎的两种开发方式的区别,并动手开发一个自己的模板引擎,以便加深对smarty模板引擎工作机制的理解。 在没有使用Smarty模板引擎的情况下,我们都是将PHP程序和网页模板合在一起编辑的,好比下面的源代码: ~~~ <?php$title="深处浅出之Smarty模板引擎工作机制";$content="Smarty模板引擎原理流程图";$auth="MarcoFly";$website="www.MarcoFly.com";?><!DOCTYPE HTML><html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title><?php echo $title?></title></head><body><p>内容:<?php echo $content?></p><p>作者:<?php echo $auth?></p><p>网址:<?php echo $website?></p></body></html> ~~~ 输出到浏览器的结果截图: ![](http://pic002.cnblogs.com/images/2011/350329/2011121022394428.jpg) 查看HTML源代码: ~~~ <!DOCTYPE HTML><html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title>深处浅出之Smarty模板引擎工作机制</title></head><body><p>内容:Smarty模板引擎原理流程图</p><p>作者:MarcoFly</p><p>网址:www.MarcoFly.com</p></body></html> ~~~ 程序比较小的情况下这种开发方式尚且不方便,一旦要开发一个大的WEB项目,就必须得使用到模板引擎。 ~~~ 使用模板引擎的情况下: ~~~ ~~~ 我们的开发方式将有所改变,美工人员只管做模板,后台开发人员专心写自己的程序。 ~~~ ~~~ 一个web项目就可以分为模板文件和PHP程序了 ~~~ ~~~ 比如: ~~~ ~~~ 美工人员就可以这样编辑网页模板文件: ~~~ ~~~ index.dwt源代码 ~~~ ~~~ <!DOCTYPE HTML><html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title><{$title}></title></head><body><p>内容:<{$content}></p><p>作者:<{$auth}></p><p>网址:<{$website}></p></body></html> ~~~ ~~~ 而后台WEB开发人员可以专注于PHP代码的书写: ~~~ ~~~ index.php ~~~ ~~~ <?php include "./Smarty.ini.php"; $title="深处浅出之Smarty模板引擎工作机制"; ~~~ ~~~ $content="Smarty模板引擎工作机制流程图"; $auth="MarcoFly"; $website="www.MarcoFly.com"; $tpl->assign("title",$title); $tpl->assign("content",$content); $tpl->assign("auth",$auth); $tpl->assign("website",$website); $tpl->display("index.dwt");?> ~~~ ~~~ 从以上两段简单的演示代码可以看出,前台模板文件没有涉及到任何关于PHP的代码,只有几个看似陌生的标签<{$title}>和<{$content}>,而后台的php程序代码也没有涉及到前台的HMTL代码 ~~~ ~~~       参考下图对比这两种开发方式的区别 ~~~ ![](http://pic002.cnblogs.com/images/2011/350329/2011121018464280.gif) ~~~ 通过对比,我们得出结论:在使用模板引擎后,原先需要使用PHP编写的地方,现在只需要用模板引擎提供标签的形式来代替了。 ~~~ ~~~ 注:Smarty模板引擎默认的标签形式是{$xxx},如,{$title},{$content} ~~~ ~~~ 当然我们可以初始化为自己想要的标签形式,如我将其初始化为:<{$xxx}>的形式),如,<{$title}>、<{$content}> ~~~ ~~~ 不知各位看官有木有觉得奇怪,<{$title}>、<{$content}>根本就不是PHP的语法形式,那最终又是如何被输出到客户的浏览器中的,是否另有玄机?带着这个疑问,我们继续深究...... ~~~ ~~~   其实,这一切的一切都是由Smarty模板引擎这双神秘的手在“暗中操作”着,经过Smarty模板引擎的“暗中操作”之后,起初的模板文件(index.dwt)经过Smarty“成功手术”之后,被改造为能在服务器端执行的PHP代码文件。 ~~~ ~~~ 想看看模板文件(index.dwt)和后台的PHP程序(index.php)经过“手术”(即编译)之后的庐山真面目吗? ~~~ ~~~ 在此贴上经过模板引擎编译之后的编译文件的源代码: ~~~ ~~~ <!DOCTYPE HTML><html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title><?php echo $this->arr["title"] ?></title></head><body><p>内容:<?php echo $this->arr["content"] ?></p><p>作者:<?php echo $this->arr["auth"] ?></p><p>网址:<?php echo $this->arr["website"] ?></p></body></html> ~~~ ~~~ 看到这里,各位看官是否恍然大悟,原来Smarty模板引擎的工作就是:将前台美工人员编写的模板文件(index.dwt)和后台开发人员编写的PHP程序(index.php)整合在一起,经过编译这一步骤之后,原先的模板标签被替换成了php代码。 ~~~ ~~~ 为了方便大家理解,我简单的做了一张代码流程图: ~~~ ![](http://pic002.cnblogs.com/images/2011/350329/2011121021571753.gif) ~~~ 接下来根据以下的Smarty模板引擎原理流程图开发一个自己的模板引擎用于学习,以便加深理解。 ~~~ ![](http://pic002.cnblogs.com/images/2011/350329/2011121021105620.gif)   Smarty模板引擎的原理,其实是这么一个过程:   把模板文件编译成php文件,然后每次都去读取下模板的修改时间,没有修改就不编译。然后include这个“编译”后的PHP文件。   所谓编译也就是模板用正则替换成含PHP代码的过程。   实际上并不会每次请求都编译,所以性能尚可。    模板文件和php程序文件经过模板引擎的编译后合成为一个文件,即编译后的文件。 接下来,我们根据该原理流程写一个简单的模板引擎。。。。。。 **  先贴上核心代码:** **  Smarty.class.php文件** ~~~ <?php class Smarty{ public $template_dir;//模板目录 public $compile_dir;//编译目录 public $arr=array();//定义一个数组,用以存放assign中的第二个参数传过来的值 public function __construct($template_dir="../templates",$compile_dir="../templates_c"){ $this->template_dir=$template_dir;//模板目录 $this->compile_dir=$compile_dir; //编译目录 } public function assign($content,$replacment=null){ if($content!=""){ //如果指定模板变量,才将要赋的值存储到数组中 $this->arr[$content]=$replacment; } } public function display($page){ $tplFile=$this->template_dir."/".$page;//读取模板文件,注意:如果模板目录下还有子目录,记得要写完整,比如,$smarty->display('Default/index.tpl') if(!file_exists($tplFile)){ return; } $comFile=$this->compile_dir."/"."com_".$page.".php"; $tplContent=$this->con_replace(file_get_contents($tplFile));//将smarty标签替换为php的标签 file_put_contents($comFile,$tplContent); include $comFile; } public function con_replace($content){ $pattern=array( '/<{\s*\$([a-zA-Z_][a-zA-Z_0-9]*)\s*}>/i' ); $replacement=array( '<?php echo $this->arr["${1}"] ?>' ); return preg_replace($pattern,$replacement,$content); } }?> ~~~ **Smarty.class.php****代码解释:** * $template_dir  指定模板文件的目录 * $compile_dir   指定编译后的模板文件的目录 * 构造函数      public function __construct($template_dir="../templates",$compile_dir="../templates_c")     {                              $this->template_dir=$template_dir;            $this->compile_dir=$compile_dir;     }     默认情况下,Smarty模板引擎将把templates目录用于存放模板文件,templates_c用于存放编译后的文件      那为何要$replacement的值保存到数组中呢?      其实内部操作是这么一个流程:将**$replacement值保存到数组--->读取模板文件(index.dwt,由display函数完成)--->将数组中的值匹配给模板文件中的变量(由con_replace()函数完成)--->将替换后的模板文件写入到编译文件中(com_index.dwt.php)--->输出编译后的PHP文件** * dispaly($page)函数接收一个参数,即要输出的模板文件(index.dwt) * 首先,将模板文件的路径赋给$tplFile($tplFile=$this->template_dir."/".$page)   * 判断模板文件是否存在,如果不存在,就没必要加载了,直接return * 指定一个编译文件,以便存放替换变量后的模板文件 * 通过函数file_get_contents()读取模板文件,并通过函数conf_replace()替换掉模板中的smarty标签 * 将替换变量后的模板文件通过file_put_contents()写入到编译文件中 * 将编译后的文件include进来,即可输出编译后的文件 * 函数con_replace($content)用于替换模板文件(index.dwt)中的变量,即将php中的变量值赋给模板中的变量     * 通过一个可以匹配形式的正则表达式匹配模板文件中的内容,并将匹配到的值替换为的形式 * 匹配到内容,并将替换后的内容返回 ~~~ /*Smarty.ini.php文件:用于完成初始化smarty的工作*/<?php include "./libs/Smarty.class.php"; $tpl=new Smarty(); $tpl->template_dir="./Tpl"; $tpl->compile_dir="./Compile";?> ~~~ ~~~ <!--模板文件--><!DOCTYPE HTML><html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title><{$title}></title></head><body><p>内容:<{$content}></p><p>作者:<{$auth}></p><p>网址:<{$website}></p></body></html> ~~~ ~~~ /*index.php文件*/<?php include "./Smarty.ini.php"; $title="深入浅出之Smarty模板引擎工作机制"; $content="Smarty模板引擎工作机制流程图"; $auth="MarcoFly"; $website="www.MarcoFly.com"; $tpl->assign("title",$title); $tpl->assign("content",$content); $tpl->assign("auth",$auth); $tpl->assign("website",$website); $tpl->display("index.dwt");?> ~~~ 该index.php就是PHP程序员编写的,可以从数据库中获取各种想要的数据,并保存到变量中,然后简单的调用assign()函数将数据保存到数组中,并通过display()函数将编译文件输出 注:此编译文件是php文件,通过服务器端执行,将结果输出的客户端的浏览器上 分析到这里,我们回过头来分析下在[**深入浅出之Smarty模板引擎工作机制(一)**](http://www.cnblogs.com/hongfei/archive/2011/12/10/Smarty-one.html)中给出的关于编译后的文件代码: ~~~ <!DOCTYPE HTML><html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"><title><?php echo $this->arr["title"] ?></title></head><body><p>内容:<?php echo $this->arr["content"] ?></p><p>作者:<?php echo $this->arr["auth"] ?></p><p>网址:<?php echo $this->arr["website"] ?></p></body></html> ~~~ 由于我们已经通过**assign()函数**,将要赋给模板标签中变量的值保存到了数组中了,即此时编译后的模板文件,可以直接输出该数组中的值了。 举个例子: ~~~ $title="深入浅出之Smarty模板引擎工作机制"; ~~~ ~~~ $tpl->assign("title",$title); ~~~ ~~~ 当执行了以上两句代码后,在数组$arr中就存放着下标为:title,值为:深入浅出之Smarty模板引擎工作机制的关联数组了。 ~~~ ~~~ 此时,就可以直接通过$this->arr['title']直接输出该数组的值。 ~~~ ~~~ 至于对如何从<{$title}> ---> <?php echo $this->arr['title']?> 的转换,不懂的读者可以再仔细看下con_replace()函数。 ~~~ * * * 有了以上几个文件之后,我们在浏览器中访问index.php文件将得到以下结果: ![](http://pic002.cnblogs.com/images/2011/350329/2011121021375145.jpg) 到此,我们“开发”了一个自己的模板引擎,并且测试成功,当然,这只是供交流学习之用。