花了差不多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相似。

ecshop源码分析:smarty模板类相关推荐

  1. 转载 ECSHOP 源码分析(includes/init.php)

    Code: 转载  ECSHOP 源码分析(includes/init.php) 收藏 <?php /** * ECSHOP 前台公用文件 * ========================= ...

  2. springfox源码_springfox 源码分析(四) 配置类初始化

    时间:2019-5-23 12:46:50 地点:单位.家中 @EnableSwagger2 有了二三章的理解,此时我们再来看EnableSwagger2注解的内容 @Retention(value ...

  3. PyTorch 源码分析:Optimizer类

    PyTorch对Optimizer类的实现大部分都在Python上,只有计算用到了C++的部分,所以还是可以继续分析的. 总览 Optimizer类是所有具体优化器类的一个基类.下面一幅图表示一下. ...

  4. Redis源码分析之工具类util

    在redis源码中的辅助工具类中,主要包括大小端转换.SHA算法以及util.h中对应的算法. 大小端转换: LittleEndian:低位字节数据存放于低地址,高位字节数据存放于高地址. BigEn ...

  5. php源码哪些文件是主程序,ThinkPHP源码分析之核心类文件的加载

    研究了下TP的加载机制,以下是我的一些总结: 1.首先由应用入口文件index.php引入TP入口文件ThinkPHP.php 2.ThinkPHP.php里主要是定义一些系统常量,URL模式定义,系 ...

  6. 集合框架源码分析四(Collections类详细分析)

    我认为Collections类主要是完成了两个主要功能  1.提供了若干简单而又有用的算法,比如排序,二分查找,求最大最小值等等.  2.提供对集合进行包装的静态方法.比如把指定的集合包装成线程安全的 ...

  7. 描述一下JAVA的加载过程_JVM源码分析之Java类的加载过程

    简书 占小狼 转载请注明原创出处,谢谢! 趁着年轻,多学习 背景 最近对Java细节的底层实现比较感兴趣,比如Java类文件是如何加载到虚拟机的,类对象和方法是以什么数据结构存在于虚拟机中?虚方法.实 ...

  8. 【muduo源码分析】Buffer类的设计

    目录 1.muduo的IO模型 2.为什么 non-blocking 网络编程中应用层 buffer 是必须的? 2.1 TcpConnection 必须要有 output buffer 2.2 Tc ...

  9. ecshop index.php,ecshop  源码分析01 (index.php)

    //ecshop 2.7.2 // define是php里定义常量用的.第一个参数是常量名,第二个是常量的值. // 它定义这个常量的作用是防止被引用文件的非法载入. // 根据某人的说法, 挂个鸟牌 ...

最新文章

  1. DesignPattern(四)结构型模式(下)
  2. 登录工程:传统 Web 应用中的身份验证技术
  3. Html控件和Web控件(转)
  4. 史上最全总结!爬虫常见加密解密算法
  5. gsonformat插件_吐血推荐珍藏的IDEA插件
  6. Bootstrap3 模态对话框的尺寸
  7. Struts2 stracture
  8. shell mysql 取值_shell 脚本中获取mysql多个字段的值
  9. Tomcat7基于Redis的Session共享
  10. spf打包解包_SPF’校园管理项目实训-1
  11. 电子产品EMC不合格,如何整改?
  12. Mirth Connect 第二章 什么是通道?
  13. 我用 Python 自制成语接龙小游戏,刺激!
  14. 为什么html中图片显示不出来,网页图片显示不出来是什么原因?
  15. 三角函数π/2转化_浅谈三角函数导数综合题(1)
  16. python基础知识学习
  17. 邮箱客户端 gmail支持_如何联系Gmail支持
  18. Django入门 | 官方文档带你快速入门
  19. 量子计算机能为我们做什么,为实现量子计算,我们还需要做些什么
  20. 图解:什么是 5G?5G 为什么那么屌?

热门文章

  1. KEIL、uVision、RealView、MDK、KEIL C51区别
  2. ubuntu下安装Google谷歌浏览器(64位系统)
  3. Element学习使用
  4. 进程互斥锁,队列,IPC进程间通信,生产者与消费者,线程,线程对象的属性,先行互斥锁...
  5. 电脑数据迁移高招,怎么把旧电脑的数据迁移到新电脑
  6. 剑指Offer面试题:31.两个链表的第一个公共节点
  7. 分享99个PHP源码,总有一款适合您
  8. 太秀了!用Pandas秒秒钟搞定24张Excel报表,还做了波投放分析!
  9. Udacity Sparkify项目
  10. ssl证书是什么,ssl证书有什么作用