PHP核心之模板引擎Smarty
Smarty
Smarty简介
- 概念
- 为了分工合作,模板页面中最好不要出现PHP的代码
- 需要将表现和内容相分离
官方Smarty
概念
- Smarty是用PHP编写的优秀的模板引擎
- Smarty可以实现前端开发人员和后台程序员分离
- 采用Smarty编写的程序可以获得最大速度的提高
- 需要实时更新的内容和小项目不适合使用Smarty
官方地址
www.smarty.net
Smarty常用属性
public $left_delimiter = "{";
左界定public $right_delimiter = "}";
右界定protected $template_dir = array('./templates/');
默认模板目录protected $compile_dir = './templates_c/';
默认混编目录protected $config_dir = array('./configs/');
默认配置目录protected $cache_dir = './cache/';
默认缓存目录
Smarty常用方法
public function setTemplateDir(){}
设置模板文件夹public function setConfigDir(){}
设置配置文件夹public function setCompileDir(){}
设置混编文件夹public function setCacheDir(){}
设置缓存文件夹
小试牛刀
- 将libs目录拷贝到站点下,改名为Smarty
- 创建模板目录templates,目录下新建index.html
- 创建混编目录templates_c
- 在站点下创建文件index.php
<?phprequire './Smarty/Smarty.class.php';$smarty=new Smarty();$smarty->assign('title','锄禾日当午');$smarty->left_delimiter='{{';//更改左界定$smarty->right_delimiter='}}';//更改右界定$smarty->setTemplateDir('./templates/');//设置模板目录$smarty->setCompileDir('./templates_c/');//设置混编目录$smarty->display('index.html');?>
# index.html<body>{{$title}}</body>
Smarty演化
演化一:Smarty生成混编文件
- html文件
# index.html<body> {$title}</body>
- php文件
# index.php<?php$title= 'Smarty';$str=file_get_contents('./index.html');$str=str_replace('{','<?php echo ',$str); //替换左大括号$str=str_replace('}',';?>',$str); //替换右大括号file_put_contents('./index.html.php', $str);//写入混编文件require './index.html.php';//包含混编文件?>
- 生成文件
# index.html.php<body> <?php echo $title;?></body>
- 相当于代码
<?php $title= 'Smarty';?><body> <?php echo $title;?></body>
演化二:Smarty封装
- 概念
- 由于每个页面都要替换定界符,所以需要将替换定界符的代码封装起来
- 由于封装在类中,所有访问的方法需要通过面向对象的方式来访问
- 需要将外部的变量赋值到对象的内部
- 要通过面向对象的方式访问
# Smarty.class.php<?phpclass Smarty{private $tpl_var=array();//赋值public function assign($k,$v){$this->tpl_var[$k]=$v;}/**作用:编译模板*@param $tpl string 模板的路径*/public function compile($tpl){$com_file=$tpl.'.php'; //混编文件地址$str=file_get_contents($tpl);$str=str_replace('{$','<?php echo $this->tpl_var[\'',$str);//替换左大括号$str=str_replace('}','\'];?>',$str); //替换右大括号file_put_contents($com_file, $str); //写入混编文件require $com_file; //包含混编文件}}?>
# index.html<body> {$title}</body>
# index.php<?phprequire './Smarty.class.php';$smarty=new Smarty();$smarty->assign('title','我的祖国');$smarty->compile('./index.html');?>
演化三:有条件的生成混编文件
- 概念
- 混编文件存在并且是最新的就直接包含,否则就重新生成
- 板文件修改时间 < 混编文件修改时间 => 混编文件是最新的
# Smarty.class.php<?phpclass Smarty{private $tpl_var=array();//赋值public function assign($k,$v){$this->tpl_var[$k]=$v;}/**作用:编译模板*@param $tpl string 模板的路径*/public function compile($tpl){ $com_file=$tpl.'.php'; //混编文件地址 //文件存在,并且模板文件修改时间<混编文件修改时间if(file_exists($com_file) && filemtime($tpl)<filemtime($com_file)) require $com_file; else{ $str= file_get_contents($tpl); $str= str_replace('{$','<?php echo $this->tpl_var[\'',$str);//替换左大括号 $str= str_replace('}','\'];?>',$str); //替换右大括号 file_put_contents($com_file, $str); //写入混编文件 require $com_file; //包含混编文件 } }}?>
演化四:文件分类存放
- 目录
- 模板文件:view
- 混编文件:viewc
- Smarty文件:smarty.class.php
# Smarty.class.php<?phpclass Smarty{public $template_dir='./templates/';//默认模板目录public $templatec_dir='./templates_c/';//默认混编目录private $tpl_var=array();//赋值public function assign($k,$v){$this->tpl_var[$k]=$v;}/**作用:编译模板*@param $tpl string 模板的名字*/public function compile($tpl){$tpl_file=$this->template_dir.$tpl;//拼接模板地址$com_file=$this->templatec_dir.$tpl.'.php';//混编文件地址//文件存在,并且模板文件修改时间<混编文件修改时间if(file_exists($com_file) && filemtime($tpl_file)<filemtime($com_file))require $com_file;else{$str=file_get_contents($tpl_file);$str=str_replace('{$','<?php echo $this->tpl_var[\'',$str);//替换左大括号$str=str_replace('}','\'];?>',$str);//替换右大括号file_put_contents($com_file, $str);//写入混编文件require $com_file;//包含混编文件}}}?>
# index.php<?phprequire './Smarty/Smarty.class.php';$smarty=new Smarty();$smarty->template_dir='./view/';//更改模板目录$smarty->templatec_dir='./viewc/';//更改混编目录$smarty->assign('title','Sunny');$smarty->compile('index.html');?>
演化五:封装编译方法
- 概念
- 编译的方法是smarty的核心方法
- 核心方法一般是不可以直接调用,需要进行二次封装
# Smarty.class.php<?phpclass Smarty{public $template_dir='./templates/';//默认模板目录public $templatec_dir='./templates_c/';//默认混编目录private $tpl_var=array();//赋值public function assign($k,$v){$this->tpl_var[$k]=$v;}public function display($tpl){require $this->compile($tpl);}/**作用:编译模板*@param $tpl string 模板的名字*/private function compile($tpl){$tpl_file=$this->template_dir.$tpl;//拼接模板地址$com_file=$this->templatec_dir.$tpl.'.php';//混编文件地址//文件存在,并且模板文件修改时间<混编文件修改时间if(file_exists($com_file) && filemtime($tpl_file)<filemtime($com_file))return $com_file;else{$str=file_get_contents($tpl_file);$str=str_replace('{$','<?php echo $this->tpl_var[\'',$str);//替换左大括号$str=str_replace('}','\'];?>',$str);//替换右大括号file_put_contents($com_file, $str);//写入混编文件return $com_file;//包含混编文件}}}?>
# index.php<?phprequire './Smarty/Smarty.class.php';$smarty=new Smarty();$smarty->template_dir='./view/';//更改模板目录$smarty->templatec_dir='./viewc/';//更改混编目录$smarty->assign('title','Sunny');$smarty->display('index.html');?>
Smarty注释
语法
{* *}
说明
- smarty注释在源码中看不见
- 若smarty的定界符是
{* *}
,则它的注释是{** **}
Smarty变量
- 概念
- Smarty中变量有三种,普通变量、配置变量、保留变量
普通变量
- 概念
- 普通变量就是自定义变量
- 自定义变量可以在PHP中定义
$smarty->assign('key','value');
- 自定义变量可以在模板中定义
{assign var='变量名' value='值'}
- 自定义变量的简化写法
- {$key='value'}
# index.php<?phprequire './Smarty/Smarty.class.php';$smarty=new Smarty();$smarty->assign('name','Sunny');$smarty->left_delimiter='{{';//更改左界定$smarty->right_delimiter='}}';//更改右界定$smarty->setTemplateDir('./templates/');//设置模板目录$smarty->setCompileDir('./templates_c/');//设置混编目录$smarty->display('index.html');?>
# index.html<body>姓名:{{$name}}<br>{{assign var='age' value='28'}}年龄:{{$age}}<br>{{$grade='高三8班'}}班级:{{$grade}}<br></body>
保留变量
概念
- Smarty中有一个特殊的保留变量(内置变量)
- 类似于PHP中的所有的超全局变量、常量、时间等信息
内置变量
{$smarty.get.name}
获取get提交的name的值{$smarty.post.name}
获取post提交的name的值{$smarty.request.name}
获取get和post提交的name的值{$smarty.cookies.name}
获取cookie中的name的值{$smarty.session.name}
获取session中的name的值{$smarty.const.name}
获取常量定义的name值{$smarty.server.DOCUMENT_ROOT}
获取服务器的虚拟根目录地址{$smarty.config.name}
获取配置文件中的值{$smarty.now}
时间戳{$smarty.ldelim}
获取左界定{$smarty.rdelim}
获取右界定
# index.php<?phprequire './Smarty/Smarty.class.php';$smarty=new Smarty();define('name','define value');setcookie('name','cookie value');$_SESSION['name']='session value';$_POST['name']='post value';$_GET['name']='get value';$_REQUEST['name']='request value';$smarty->left_delimiter='{';//更改左界定$smarty->right_delimiter='}';//更改右界定$smarty->setTemplateDir('./templates/');//设置模板目录$smarty->setCompileDir('./templates_c/');//设置混编目录$smarty->display('index.html');?>
# index.html<body>get提交:{$smarty.get.name}<br>post提交:{$smarty.post.name}<br>request提交:{$smarty.request.name}<br>常量:{$smarty.const.name}<br>cookie的值:{$smarty.cookies.name}<br>session的值:{$smarty.session.name}<br>时间戳:{$smarty.now}<br>版本号:{$smarty.version}<br>根目录:{$smarty.server.DOCUMENT_ROOT}<br>左界定:{$smarty.ldelim}<br>右界定:{$smarty.rdelim}<br></body>
配置变量
概念
- 从配置文件中获取变量值,配置文件默认的文件夹是
configs
- 从配置文件中获取变量值,配置文件默认的文件夹是
流程
- 在站点下创建配置文件夹
configs
- 在
configs
目录下创建smarty.conf文件 - index.php PHP配置页面
- index.html 视图页面
- 在站点下创建配置文件夹
# smarty.confcolor= '#21f4b1';size='15px';
# index.php<?phprequire './Smarty/Smarty.class.php';$smarty=new Smarty();$smarty->display('index.html');?>
# index.html{config_load file='smarty.conf'} <!--引入配置文件--><style>body{color:{$smarty.config.color};font-size: {#size#}}</style><body><span>测试文本</span></body>
- 关于配置文件
- 要使用配置文件中的值,首先必须引入配置文件,通过{config_load}标签引入
- 获取配置文件中值的方法有两种
- {#变量名#}
- {$smarty.config.变量名}
- 配置文件中的节
- 在配置文件中,
[ ]
表示配置文件的段落
- 在配置文件中,
- 配置文件说明
- 全局的一定要写在节的前面
- 配置文件中
[ ]
表示节 - 配置文件中的注释是
#
- 通过
section
引入配置文件中的段落
# smarty.confcolor= #1e6bec;size=32px;[spring]# 配置文件中的段落color=#9cec1e;size=24px;[winter]color=#ec1ee5;size=56px;
# index.html{config_load file='smarty.conf' section='winter'} <!--引入配置文件--><style>body{color:{$smarty.config.color};font-size: {#size#}}</style><body><span>测试文本</span></body>
smarty运算符
概念
- Smary中的运算符和PHP是一样的
- 除此以外,Smarty还支持如下的运算符
运算符
eq
相等(equal)neq
不等于(not equal)gt
大于(greater than)lt
小于(less than)lte
小于等于(less than or equal)gte
大于等于(great than or equal)is even
是偶数is odd
是奇数is not even
不是偶数is not odd
不是奇数not
非mod
求模取余div by
被整除is [not] div by
能否被某数整除{if $smarty.get.age is div by 3}...{/if}
is [not] even by
商的结果是否为偶数is [not] odd by
商的结果是否为奇数
判断
概念
- 在判断中是可以使用PHP函数的
语法
{if 条件}
{elseif 条件}
{else}
{/if}
# index.php<?phprequire './Smarty/Smarty.class.php';$smarty=new Smarty();$smarty->display('index.html');?>
# index.html{config_load file='smarty.conf' section='winter'} <!--引入配置文件--><style>body{color:{$smarty.config.color};font-size: {#size#}}</style><body>{if is_numeric($smarty.get.score)}{if $smarty.get.score gte 90}<span>A</span>{elseif $smarty.get.score gte 80}<span>B</span>{elseif $smarty.get.score gte 70}<span>C</span>{elseif $smarty.get.score gte 60}<span>D</span>{elseif $smarty.get.score lt 60}<span>E</span>{/if}{else}<span>不是数字</span>{/if}<hr>{if is_numeric($smarty.get.score)}{if $smarty.get.score is even}<span>是偶数</span>{elseif $smarty.get.score is odd}<span>是奇数</span>{/if}{/if}</body>
数组
- 概念
- Smarty中访问数组的方式有两种
- 数组[下标]
- 数组.下标
- Smarty中访问数组的方式有两种
# index.php<?phprequire './Smarty/Smarty.class.php';$smarty=new Smarty();$stu= array('Sunny', 'Jerry');$emp= array('name'=>'Marry', 'sex'=>'girl');$goods= array( array('name'=>'ceilphone','price'=>2560), array('name'=>'notebook','price'=>3600));$smarty->assign('stu',$stu);$smarty->assign('emp',$emp);$smarty->assign('goods',$goods);$smarty->display('index.html');?>
# index.html{config_load file='smarty.conf'} <!--引入配置文件--><style>body{color:{$smarty.config.color};font-size: {#size#}}</style><body><div>学生:{$stu[0]} {$stu[1]}</div><div>雇员:{$emp['name']} {$emp.sex}</div><div>商品:</div><ul><li>{$goods[0]['name']}</li><li>{$goods[0].price}</li><li>{$goods[1]['name']}</li><li>{$goods[1].price}</li></ul></body>
循环
- 概念
- Smarty中支持的循环有:
{for} {while} {foreach} {section}
- 对于开发来说用的最多就是
{foreach}
循环
- Smarty中支持的循环有:
for循环
- 语法
{for 初始值 to 结束值 [step 步长]} {/for}
- 默认步长是1
# index.html<body>{for $i=0 to 10 step 2}<div>一江春水向东流</div>{/for}</body>
while循环
- 语法
{while 条件} {/while}
# index.html<body>{$i=0}{while $i<5 }<div>{$i } 一江春水向东流</div>{/while}</body>
foreach
概念
- 既能遍历关联数组也能遍历索引数组
语法
{foreach 数组 as $k=>$v}
{foreachelse}
{/foreach}
foreach的属性
@index
从0开始的索引@iteration
从1开始的编号@first
是否是第一个元素@last
是否是最后一个元素
# index.php<?phprequire './Smarty/Smarty.class.php';$smarty=new Smarty();$stu= array( 'first'=>'Sunny', 'second'=>'Jerry', 'third'=>'Marry', 'forth'=>'Tommy');$smarty->assign('stu',$stu);$smarty->display('index.html');?>
# index.html<body><table border='1' bordercolor='#000' width='780'><tr><th>是否是第一个元素</th><th>索引</th><th>编号</th><th>键</th><th>值</th><th>是否是最后一个元素</th></tr>{foreach $stu as $k=>$v}<tr><td>{if $v@first==1}<span>是第一个元素</span>{/if}</td><td>{$v@index}</td><td>{$v@iteration}</td><td>{$k}</td><td>{$v}</td><td>{if $v@last==1}<span>是最后一个元素</span>{/if}</td></tr>{foreachelse}没有输出{/foreach}</table></body>
section
概念
- section不支持关联数组,只能遍历索引数组
语法
{section name=自定义名字 loop=数组} {/section}
# index.php<?phprequire './Smarty/Smarty.class.php';$smarty=new Smarty();$stu= array('Sunny','Jerry','Marry','Tommy');$smarty->assign('stu',$stu);$smarty->display('index.html');?>
# index.html<body><table border='1' bordercolor='#000' width='780'><tr><th>是否是第一个元素</th><th>索引</th><th>编号</th><th>值</th><th>是否是最后一个元素</th></tr>{section name=s loop=$stu}<tr><td>{if $smarty.section.s.first ==1}是第一个元素{/if}</td><td>{$smarty.section.s.index}</td><td>{$smarty.section.s.iteration}</td><td>{$stu[s]}</td><td>{if $smarty.section.s.last==1}是最后一个元素{/if}</td></tr>{sectionelse}没有输出{/section}</table></body>
函数
- 概念
- Smarty的内置函数就是封装的PHP的关键字
- 函数有两种,自定义函数和内置函数
内置函数
{$var=...}
变量赋值- 这是{assign}函数的简写版
- 你可以直接赋值给模版,也可以为数组元素赋值
{assign}
赋值- 用来在模板运行时为模板变量赋值
{while}
循环- Smarty的{while}循环与php的while语句一样富有弹性
{for}
循环- {for}、{forelse}标签用来创建一个简单循环
{foreach}
遍历- {foreach}与{section}循环相比更简单、语法更干净
- 也可以用来遍历关联数组
{section}
遍历数组- 支持循序索引遍历数组中的数据(支持一次性读取多维数组)
{function}
函数- 用来在模板中创建函数,可以像调用插件函数一样调用它们
{if}
条件- Smarty的{if}语句与php的if语句一样富有弹性
{include}
包含- {include}标签用于在当前模板中包含其它模板
{nocache}
禁止缓存- {nocache}用来禁止模版块缓存
变量修饰器
变量修饰器
- 概念
- 变量修饰器的本质就是PHP函数,用来转换数据
- 将PHP的关键字或函数封装成标签称为函数
- 将PHP关键字封装成smarty关键字称为修饰器
- 内部的本质都是PHP函数或PHP关键字
|
称为管道运算符,将前面的参数传递后后面的修饰器使用
# index.php<body>转成大写:{'abc'|upper} <br>转成小写:{'ABC'|lower} <br>默认值:{$add|default:'地址不详'}<br>去除标签:{'<b>你好吗</b>'|strip_tags}<br>实体转换:{'<b>你好吗</b>'|escape}<br>日期:{$smarty.now|date_format:'%Y-%m-%d %H:%M:%S'}<br>多个管道连续使用:{'<b>boy</b>'|strip_tags|upper}<br></body>
自定义变量修饰器
概念
- 变量修饰器存放在plugins目录中
规则
- 文件的命名规则:modifier.变量修饰器名称.php
- 文件内方法命名规则:smarty_modifier_变量修饰器名称(形参...){}
例题
- 在plugins目录中创建modifier.cal.php页面
- 在模板中调用
- 10作为第一个参数传递
- 参数之间用冒号分隔
# modifier.cal.php<?phpfunction smarty_modifier_cal($num1,$num2,$num3){return $num1 $num2 $num3;}?>
# index.html{10|cal:20:30}
避免Smarty解析
概念
- Smarty的定界符和css、js中的大括号产生冲突的时候
- css、js中的大括号不要被Smarty解析
方法
- 更换定界符
- 左大括号后面添加空白字符
{literal} {/literal}
- smarty不解析{literal} {/literal}中的内容
# index.html<style>{literal}body{color: #FF0000;}{/literal}</style>
缓存
- 概念
- 缓存一般包括页面缓存、空间缓存、数据缓存
- smarty的缓存是页面缓存
开启缓存
- 开启缓存
$smarty->caching=true|1;
缓存的更新
- 方法
- 删除缓存,系统会重新生成新的缓存文件
- 更新了模板文件,配置文件,缓存自动更新
- 过了缓存的生命周期,默认是3600秒
- 强制更新
# index.php<?phprequire './Smarty/smarty.class.php';$smarty=new Smarty();$smarty->caching=true;//开启缓存if(date('H')>=9)$smarty->force_cache=true;//强制更新缓存$smarty->display('index.html');?>
缓存的生命周期
- 语法
$smarty->cache_lifetime=-1 | 0 | N
- -1:永远不过期
- 0:立即过期
- N:有效期是N秒,默认是3600秒
$smarty->cache_lifetime=3;//缓存的生命周期
局部不缓存
- 不缓存的方法
- 变量不缓存
{$变量名 nocache}
- 整个块不缓存
{nocache} {/nocache}
- 变量不缓存
{$smarty.now nocache}
{nocache}{$smarty.now}{/nocache}
缓存分页
概念
- 通过识别id来缓存分页、集合
语法
$smarty->display(模板,识别id)
# index.php<?phprequire './Smarty/smarty.class.php';$smarty=new Smarty();$smarty->caching=1;$smarty->display('index.html',$_GET['pageno']);?>
# index.html<body>这是第{$smarty.get.pageno}页</body>
缓存集合
- 概念
- 每个组合都会产生缓存
# index.php<?phprequire './Smarty/smarty.class.php';$smarty=new Smarty();$smarty->caching=1;$color=$_GET['color'];$size=$_GET['size'];$smarty->display('7-demo.html',"$color|$size");?>
# index.html<body>颜色:{$smarty.get.color}<br>大小:{$smarty.get.size}<br></body>
清除缓存
- 语法
$smarty->clearCache(模板,[识别id])
清除缓存$smarty->clearAllCache();
清除所有缓存
# index.php<?phprequire './Smarty/smarty.class.php';$smarty=new Smarty();//$smarty->clearCache('7-demo.html',1);//$smarty->clearCache('7-demo.html','red|10');//$smarty->clearCache('7-demo.html');$smarty->clearAllCache();//清除所有缓存?>
将smarty集成到项目中
- 流程
- 将smarty拷贝到Lib目录下
- 实现smarty类的自动加载
- 创建混编目录,并且定义混编目录地址
Viewc
为混编目录
- 由于前后台都要启动模板,所以应该在基础控制器中实例化smarty
- 在控制器中使用smarty
- 在模板中更改
# Framework/Core/Framework.class.phpprivate static function initRoutes(){$p=$_GET['p']??$GLOBALS['config']['app']['dp'];$c=$_GET['c']??$GLOBALS['config']['app']['dc'];$a=$_GET['a']??$GLOBALS['config']['app']['da'];$p=ucfirst(strtolower($p));$c=ucfirst(strtolower($c));//首字母大写$a=strtolower($a);//转成小写define('PLATFROM_NAME', $p); //平台名常量define('CONTROLLER_NAME', $c); //控制器名常量define('ACTION_NAME', $a); //方法名常量define('__URL__', CONTROLLER_PATH.$p.DS); //当前请求控制器的目录地址define('__VIEW__',VIEW_PATH.$p.DS); //当前视图的目录地址define('__VIEWC__', APP_PATH.'Viewc'.DS.$p.DS); //混编目录}private static function initAutoLoad(){spl_autoload_register(function($class_name){//Smarty类存储不规则,所以将类名和地址做一个映射$map=array('Smarty' => LIB_PATH.'Smarty'.DS.'Smarty.class.php');$namespace= dirname($class_name); //命名空间$class_name= basename($class_name); //类名if(in_array($namespace, array('Core','Lib'))) //命名空间在Core和Lib下$path= FRAMEWORK_PATH.$namespace.DS.$class_name.'.class.php';elseif($namespace=='Model') //文件在Model下$path=MODEL_PATH.$class_name.'.class.php';elseif($namespace=='Traits') //文件在Traits下$path=TRAITS_PATH.$class_name.'.class.php';elseif(isset($map[$class_name]))$path=$map[$class_name];else //控制器$path=CONTROLLER_PATH.PLATFROM_NAME.DS.$class_name.'.class.php'; // $path=__URL__.$class_name.'.class.php';if(file_exists($path) && is_file($path))require $path;});}
# Framework/Core/Controller.class.php<?php//基础控制器namespace Core;class Controller{ protected $smarty; use \Traits\Jump; public function __construct() { $this->initSession(); $this->initSmarty(); } //初始化session private function initSession(){ new \Lib\Session(); } //初始化Smarty private function initSmarty(){ $this->smarty=new \Smarty(); $this->smarty->setTemplateDir(__VIEW__); //设置模板目录 $this->smarty->setCompileDir(__VIEWC__);//设置混编目录 }}?>
# Application/Controller/Admin/ProductsController.class.phppublic function listAction(){// 实例化数据模型$model= new \Model\ProductsModel();$list= $model->select();// 加载视图require __VIEW__.'products_list.html';$this->smarty->assign('list',$list);$this->smarty->display('products_list.html');}
# Application/View/Admin/products_list.html{foreach $list as $rows}<tr><td>{$rows['proID']}</td><td>{$rows['proname']}</td><td>{$rows['proprice']}</td><td><a href="index.php?p=Admin&c=Products&a=del&proid={$rows['proID']}" onclick="return confirm('确定要删除吗')">删除</a></td><td><a href="index.php?p=Admin&c=Products&a=edit&proid={$rows['proID']}">修改</a></td></tr>{/foreach}
赞 (0)