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)
