ecshop源码分析:smarty模板类

来源:互联网 发布:c语言连用else if 编辑:程序博客网 时间:2024/04/30 07:18
花了差不多3天半的时间,基本上把ecshop1400多行的模板类源码阅读完毕。从构造函数一行一行的阅读下去,遇到方法的调用便进去,遇到返回值又回到调用它的地方,这样来回不知道多少遍,每次阅读都让我心奋不已。之前一直都在使用smarty,却不知道它的工作原理,现在终于大概有个详细并全面的了解了,怎能不兴奋。现在,给大家分享我在看源码总结出的smarty的工作流程以及smarty标签的使用

模板类工作流程

1.首先实例化模板类,构造函数基本没做什么工作,对象变量为$smarty。调用$smarty->assign(var,value),在assign()方法里把该变量和值装入$this->_var数组中:如果var是数组,如$smarty->assign(array(‘var1’=>val1,’var2’=>val2))则在$this->_var表示为:$this->_var[‘var1’]=val1、$this->_var[‘var2’]=val2…,如果是字符串:$this->_var[‘var’]=value。

2.调用:$smarty->display(‘index.html’);display()几乎没做多少工作,而是交给其他几个函数处理:首先display()内部调用fetch(‘index.html’)方法,把模板文件名作为参数传递过去;

3.fetch()是一个处理模板文件的方法,它做了许多条件判断分别进入到不同的处理语句,最主要的是它又调用了模板类的一个方法make_compiled()模板文件名作为参数传递过去;

4.make_compiled()是一个编译模板的方法:首先取得编译文件的绝对路径(前一部分是固定的,ecshop的后台前一部分编译路径C:\AppServ\www\ecshop\temp\compiled\admin\,后一部分是根据模板文件名设定,如模板为index.html,那后一部分就是index.html.php),接下来做判断,如果模板文件的修改时间小于等于编译文件的修改时间,则直接获取编译文件(这部分还会调用一个方法,稍后再说),反之,则重新编译模板文件:将模板文件的全部内容获取(file_get_contents)并把这些内容传给fetch_str()方法,由它处理。对fetch_str()返回的内容,把他们存入编译文件(php文件)中,到这里已经完成了模板文件的编译工作,随后就是执行编译文件,向浏览器输出内容了,这个工作由_eval()方法完成,把fetch_str()返回的内容作为_eval()的实参,这个方法很简单,直接把代码粘上来:

function _eval($content){ob_start();//开启缓冲        eval('?' . '>' . trim($content));//'?'.'>'是为了闭合前面的PHP代码        $content = ob_get_contents();//获取缓冲内容        ob_end_clean();//清除缓冲区return $content; }

最后把_eval()返回的值return给fetch(),fetch()也基本原样返回给display(),最后在dislay()中echo 该返回值。

5.fetch_str()一个处理字符串的方法:他需要一个参数,即是传递过来的模板文件的内容。它的工作是把在模板文件中类似<?php或<?=或?>或language="php"的字符串转换为%%%SMARTYSP0%%%类似字符(这部分暂时还不知道为什么这样做,大概是为了清除掉php起始和闭合标签),最后的一行代码完成了它应完成的功能:

return preg_replace("/{([^\}\{\n]*)}/e", "\$this->select('\\1');", $source);
这个正在表达式的功能是对模板中的标签{}之内的内容交由方法select()处理,传递的参数就是在模板中变量说明那里说到的一个字符串,但不包括{}。如模板中有标签{$var|nl2br}传给select的参数就是’$var|nl2br’(注:这只是一个字符串,不要以为有$就是变量)。把select()的返回值替换掉模板中匹配的内容后,将所有替换的内容返回给make_compiled (),即编译完成,接下来就由make_compiled ()把这些内容存入文件里了;

6.select($tag)一个处理{}标签的方法:这个方法条件分支多,在阅读源码的时候应该一个一个分支阅读下去,遇到其他方法的调用就进去,切记不要操之过急。该方法首先判断传进来的$tag(即{}标签内的内容)是否为空,如果为空则返回’{}’即原样输出;判断$tag的首字母和尾字母是否都为*,如果是,则返回空,这部分是模板的注释,在编译文件中不会显示;判断$tag首字母是否为’$’,如果有,表示这是一个变量,把这个字符串的首字母’$’截掉后传递给get_val()方法,交给他处理。对get_val()的返回值类似:’$this->_var[‘str’]’,select()方法处理成’<?php echo $this->_var[‘str’];?>’字符串后返回给fetch_str();判断$tag首字母是否为’/’,表示这是个结束标签,如{/if}转为’<?php endif; ?>’;最后如果以上都不是,又需要经过许多判定处理,这部分的语句可以把{if}、{foreach}等解析。

7.get_val($val)一个处理smarty标签中的变量标签方法:如果$val值类似arr[0][1]、arr[str]、arr[$var]等,则替换为arr.0.1、arr.str、arr.$var并把替换后的值赋给$val覆盖原先的值;如果$val(是之前覆盖的值,如果有的话)的值包含’|’字符,’|’后面是过滤函数的名称,对$val使用$moddb =explode('|', $val); $val = array_shift($moddb);将第一个元素弹出,并把其值赋给$val,在对$moddb遍历,把过滤函数应用make_val()返回的在变量上。例如:如果$val=arr.str|nl2br则最后$val=arr.str,$moddb=array(‘nl2br’);对于arr.str和arr.$var(点号之后又有$)get_val有不同的处理方法:对于’arr.str’或’str’或’arr.0.1’,直接交由make_val()方法处理;对于’arr.$var’或’arr.$var1.$var2’,说明不仅arr是个变量,$var1和$var2也是变量,它们都存在$this->_var数组里(如果assign()注入了的话),把他们通过’.$’分开在分别交由make_val()处理,我们知道make_val()会返回类似’$this->_var[‘arr’]’的字符串,所以在get_val()中只是对’var1’和’var2’make_val()返回的字符串两侧加上’[‘、’]’,最后构成一个表示一维或多维数组的字符串:”$this->_var[‘arr’][$this->_var[‘var1’]][$this->_var[‘var2’]]”,最后将此字符串返回给select();

模板标签的使用

1.{*...*}模板的注释,在编译文件里里面的内容会为空

2.{$var}、{$arr[0]}、{$arr[$var]}、{$arr.var}、{$var1|htmlspecialchars }模板中的变量表示方式

其中{$var1|htmlspecialchars}“|”后面的字符串是对变量的过滤函数:其可以使用多种过滤函数:{$var|escape:fucstr}冒号后面的fucstr和他所代表的函数可是:

       html :  htmlspecialchars

       url   :      urlencode

       decode_url      :      urldecode

       quotes     :      addslashes

       u8_url     :      if (EC_CHARSET != 'utf-8'){ $p = 'urlencode(ecs_iconv("' . EC_CHARSET .'", "utf-8",' . $p . '))';}else{ $p = 'urlencode(' . $p . ')';}

如果没有冒号后面的默认是htmlspecialchars

还有:{$var|nl2br}       :      nl2br($var)

{$var|default}        :      empty($var)?’’:$var

{$var1|default:$var2}    :      empty($var1)?$var2:$var1

{$var|default:str}         :      empty($var)? ’str’ :$var1

{$var|truncate:number}  :      sub_str($var,number)(注:sub_str是ecshop的一个自定义函数,可以截取中文)

{$var|strip_tags}           :      strip_tags($var)

以上可在在模板类cls_template.php文件的get_val()方法里找到

3.{if}标签:用法{if $arr.str eq 1}{/if} (每个字符串至少用一个空格隔开)。关系运算符eq:==,ne或neq:!=,lt:<,le或lte:<=,gt:>,ge或gte:>=,and:&&,or:||,not:!,mod:%。以上都可以使用大写,也可以用他们本身替代。对$arr.str的处理使用get_val(‘arr.str’)方法,下面模板工作流程里会介绍,最后编译为:<?phpif($this->_var[‘arr’][‘str’] == 1): ?>。也可在{if}{/if}里使用{else}和{elseif},对{else}的处理是直接返回’<?php else: ?>’,对{elseif}的处理和{if}类似。

4.{foreach}标签:用法{foreach from=$arr item=val key=k name=n}{$val}{/foreach}key和name可以不设置。可以嵌套多个{foreach}标签,可以使用{foreachelse}。对{foreach}标签的解析方式看以查看_compile_foreach_start()函数。

5.{assign}标签:用法{assignvar=user value=hzn}用于在模板中注册变量,在编译文件中解析为:<?php $this->assign(‘user’,’hzn’); ?>。value也可以使用变量但name不行{assignvar=user value=$hzn}解析为:<?php $this->assign(‘user’,$this->_var[‘hzn’]) ?>

6.{include}标签:用法{includefile=other.html}用于包含模板文件。文件名可以加单引号护双引号。(注:other.html所用到的变量,需要从引用这个文件的模板文件的对应php文件注入)

7. {insert_scripts}标签:用法{insert_scripts files=”../js/utils.js,listtable.js”}可以引入一个或多个js脚本,多个文件之间用逗号隔开。文件以“.”开头的,表示<scripttype="text/javascript" src="../js/utils.js"></script>,没有点号开头<scripttype="text/javascript" src="js/listtable.js"></script>总会在文件名之前加上’js/’,可以在方法smarty_insert_scripts()更改。 

8.{ create_pages}标签:用法{create_pages page=1 count=10}生成一个下拉列表。可以用作分页列表。

9.{insert}标签:用法{insert name=”fuc” id=$id type=”text”}在编译文件执行时调用insert_fuc()这个函数(fuc名称可以自定),该方法可以传递一个数组作为参数:array(‘name’=>’fuc’,’id’=>$this->_var[‘id’],’type’=>’text’)。这个标签在编译文件中编译为:

<?php $k = array (  'name' => 'strlen',  'id' => $this->_var['id'],  'type' => 'text',);echo $this->_echash . $k['name'] . '|' . serialize($k) . $this->_echash;?>

初看起来让人摸不着头脑,在到display()方法去看就明白了。其实在display()已经把编译文件执行了,所以缓冲的内容里是以$this->_echash(一个很长的字符串)分成了三部分,对$k['name'] . '|' .serialize($k)进行处理再把三部分合并输出。

10.{literal}标签:用法{literal}{/literal}原样输出标签中包含的内容 

11.{cycle}标签:用法{cycle values=”blue,red,green”}循环输出values的内容,一个标签只能输出一个值,按顺序输出。 

12.{html_options}标签:用法{html_options selected=”2” options=$arr}用于输出select标签的<option>标签。selected表示初始列表选定的值,options是一个数组,该数组的键值作为<option>的value,元素值作为<option>显示的值。另一种用法将value值和显示的值分开:

{html_options values=$valArr output=$opArr selected=”2”}如果没有values,output的键值作为<option>的value 

13.{html_select_date}标签:用法{html_select_dateprefix="StartDate" time=$time start_year="-5"end_year="+1" display_days=”true” display_months=”false”}用于显示年月日的下来列表,prefix指定每个<select>name属性的前缀,如年份的<select name=”StartDateYear”>;time用来指定option的selected。start_year,end_year是年份下拉列表的开始日期和结束日期,可以是-5、+1(表示由当前日期减去或加上多少数值),也可以是2014四位数的形式;display_days和display_months如果设置为”false”则不显示天数和月数的下拉表。

14.{html_radios}标签:用法{html_radiosname="order" checked="3" options=$arr}显示单选按钮。 

15.{html_select_time}标签:用法{html_select_timeprefix="myTime" time=$time display_hours="false"}显示时间下拉表。和html_select_date相似。





0 0
原创粉丝点击