PHP_Smarty

模板

数据与表现层的标签分离

smarty是PHP 与 HTML代码的分离

小型模板类

$smarty 的工作流程:

  1. 把需要显示的全局变量,赋值塞到对象内部的属性上,一个数组中.

  2. 编译模板,把{$标签},解析成相应的代码

  3. 引入编译后的PHP文件

使用smarty的步骤:

  1. smarty是一个类,要使用,需要先引入并实例化

  2. assign赋值

  3. display --> 编译到输出

smarty缺点:

  1. 编译模板,需要消耗时间

  2. 要把变量再重新赋值一份(又倒腾一次,放在对象的属性上)

PHP文件
     *         区分 模板文件和 PHP文件,把模板和编译后的结果,放置在不同的目录中.
     *         用2个不同的属性来记录 不同的目录    
     */
      
    class Tmp {
        public $template_dir = ''; // 模版文件所在的路径
        public $compile_dir = ''; // 模板编译后存在的路径

        public $tpl_var = array(); // 接受外部的变量
        
        /**
         * 存储全局变量
         * @param {String} $key 变量名
         * @param {Mixin} $val 变量值 
         */
        public function assign( $key, $val ) {
            $this->tpl_var[$key] = $val;
        }
        
        /**
         * 调用 compile模板,和自动引入
         * @param {String} $template 模板文件名
         */
        public function display( $template ) {
            $comp = $this->compile($template);
            include($comp);
        }
                
        /**
         * 编译
         * @param {String} $template 模板文件名 (需要编译的模板文件的文件名)
         * @return {String} $comp 编译后的文件路径 
         * 
         * 把指定的模板内容读取,再编译成PHP文件
         * 
         * 最终外部执行的是,编译后的文件
         */
        public function compile( $template ) {
            
            // 读取模板内容
            $tmp = $this->template_dir . '/' . $template;
            $scoure = file_get_contents($tmp);    

            // 替换模板内容
            
            $scoure = str_replace('{$', 'tpl_var[\'', $scoure);
            $scoure = str_replace('}', '\'];?>', $scoure);
            
            
            // 把编译后的内容保存成编译后的文件
            $comp = $this->compile_dir . '/'. $template . '.php';
            
            // 判断模板是否已经存在, 加上通过 文件修改的时间来判断,模板是否已经被修改过
            if ( file_exists($comp) && filemtime($tmp) < filemtime($comp) ) {
                return $comp;
            }
            
            file_put_contents($comp, $scoure);
                        
            return $comp;                
        }
        
    }
?>

引入赋值和标签语法

smarty典型使用流程

template_dir    = './templates';
    $smarty->compile_dir = './compile';
    
    
    // 赋值
    $smarty->assign('title', 'T');
    $smarty->assign('content', 'C');
    
    // 编译
    $smarty->display('temp01.html');
    
?>

smarty可以赋值为数值,数字等值,可以是数组.

VIEW:

姓名: {$name}
年龄 {$age}
兵器 {$weapon}
姓名: {$zf.name}
年龄 {$zf.age}
兵器 {$zf.weapon}
姓名: {$guanyu[0]}
年龄 {$guanyu[1]}
兵器 {$guanyu[2]}

Controller

template_dir    = './templates';
    $smarty->compile_dir = './compile';
    
    
    $user = array(
        'name' => '刘备',
        'age' => 28,
        'weapon' => '双剑'
    );    
    
    // 赋值
    $smarty->assign($user);
    
    $zf = array(
        'name' => '张飞',
        'age' => 25,
        'weapon' => '矛'
    );    
    $smarty->assign('zf', $zf);
    
    $guanyu = array('关羽', 25, '青龙');
    $smarty->assign('guanyu', $guanyu);
    
    // 编译
    $smarty->display('liubei.html');
    
?>

smarty模板标签与css标签防止冲突

如果smarty默认定界符 {} 与 css {} 冲突
可以使用以下二种方法解决

  1. 修改smarty默认定界符{{}}

  2. 也可以用{literal}{/literal}标签,来告诉smarty,此处照常输出,不用解析

// 配置smarty的左右定界符
$smarty->left_delimiter = '{{';
$smarty->right_delimiter = '}}';          

模板变量来源

smarty标签变量的来源:
在模板中,{$title},则说明$title标签在被assign赋过值。

smarty的标签变量对应的来源,除了assign,还有那些?

  1. PHP中assign分配变量

  2. smarty的系统保留变量

  3. 从配置文件读取到的配置变量

assign

    // 引入
    require('../smarty3/libs/Smarty.class.php');
    
    // 实例化
    $smarty = new Smarty();
    
    // 配置
    $smarty->template_dir = './templates';
    $smarty->compile_dir = './compile'; 
    
    // assign 赋值
    $smarty->assign('name', '罗隐');
    $smarty->assign('poem', '我未成名君未嫁,可能俱是不如人');
    
    // 编译
    $smarty->display('shiju.html'); 

系统保留变量

系统保留变量,不用赋值,能够自动获取

{$smarty.get.id}

$smarty.开头的标签,当成系统变量来解析,如:$smarty.get.id解析成

还有以下几个系统保留变量:

  • $smarty.post

  • $smarty.session

  • $smarty.cookies

常量如何显示:
$smarty.const.常量名

{$smarty.const.HEI}

配置文件读取配置变量

注意:

  1. 配置文件,一般以.conf做后缀

  2. 配置文件的写法是:选项=值

  3. 配置smarty的config_dir,并把配置文件放在该目录下.

配置文件:

site=pink
tel='13164889431'

获取配置文件中的变量:

// 引入:
{config_load file='site.conf'}

// 显示
{$smarty.config.site}
{#tel#}

append

连着往某个标签赋值多个值,可以使用append

赋值:

$smarty->append('color', 'tan'); // _tpl_vars['color'][] = 'tan'
$smarty->append('color', 'pink'); // _tpl_vars['color'][] = 'pink'

使用:

{$color[0]}

{$color[1]}

源码:

$data->tpl_vars[ $tpl_var ]->value[] = $value;

把一个值压入一个数组

smarty赋值时还能够引用赋值

assignByRef('title', $title); // _tpl_vars['title'] = &title; // 引用赋值

这个功能在PHP5以后,意义不大,PHP5以后是写时赋值

对象赋值和引用

对象赋值

class Human {
    public $name = 'zf';
    public $age = 23;
    
    public function say() {
        return 'HELLO WORLD';
    }
    
}

$man = new Human();

$smarty->assign('man', $man);

显示:

{$man->name}
{$man->age}
{$man->say()}

模板的作用:分离PHP代码,让代码简洁,所以模板中的标签,应该尽量的只负责变量的输出.不要负责太多的逻辑判断,函数调用等.

简化模板配置

通过继承来简化模板配置

setTemplateDir('./templates');  // 模板文件位置
            $this->setCompileDir('./compile');  // 编译文件位置
            $this->setConfigDir('./conf');  // 配置文件位置
                 
        }

    } 
    
?>

标签数学运算

{$age}
{$age + 2}
年纪差为:{$age - $diffAge}

逻辑判断

IF标签要成对

{if $price < 10000 }
{$color}
{else}
TAN
{/if}

{if $smarty.get.today == 0 || $smarty.get.today == 7} 
周日
{elseif $smarty.get.today == 6}
周六
{else}
工作日
{/if}

在模板中使用逻辑判断的思考:
从分工角度看:模板只负责输出 ,不负责逻辑判断。
为什么还需要有逻辑判断? 在模板上进行逻辑判断,可以极大的简化工作.

smarty循环

for循环

for循环基本应用

赋值:

    $smarty->assign('start', 1);
    $smarty->assign('end', 9);

显示:

{for $i = $start to $end}
    {$i}
    {if $i % 3 == 0}
        
{/if} {/for}

1-100所有的奇数

{for $i=$start to 100} {if $i % 2 != 0 } {$i} {/if} {/for}

循环总次数$i@total,循环索引$i@iteration

步长属性 控制

{for $i=$start to 100 step 2} {if $i@first == $start} {$i} {elseif $i@last == $i@total} {$i} {else} {$i} {/if} {if $i@iteration % 3 == 0}
{/if} {/for}
循环总次数:{$i@total}
循环索引:$i@iteration
循环的第一次:$i@first
循环的最后一次:$i@last

foreach循环

foreach循环
典型场景,二维数组的循环
例如:新闻列表,会员列表,商品列表

赋值数据

assign($category);
    
    $smarty->display('foreach.html');    

?>

使用foreach:

商品栏目

// {foreach from=$category key=key item=$g} {foreach $category as $k=>$g} {/foreach}
序号 栏目名 栏目信息
{$g.cat_id} {$g.cat_name} {$g.intro}

循环总次数$i@total,循环索引$i@iteration

商品栏目

{foreach $category as $k=>$g} {/foreach}
序号 栏目名 栏目信息
{$g@iteration} {$g.cat_name} {$g.intro}
索引:$g@iteration
首行:$g@first
尾行:$g@last
总条数:{$g@total}

变量调节器

变量调节器:在模板中,修改变量的显示形式的一种功能.
变量调节器的本质是一个函数,这个函数,以标签对应的变量值为参数,然后运算,把返回值,显示在标签处.

内置变量调节器:

capitalize [首字符大写]
count_characters [字符计数]
cat [连接字符串]
count_paragraphs [计算段数]
count_sentences [计算句数]
count_words [计算词数]
date_format [格式化日期]
default [默认值]
escape [编码]
indent [缩进]
lower [小写]
nl2br [换行符替换成 
] regex_replace [正则替换] replace [替换] spacify [插空] string_format [字符串格式化] strip [去除(多余空格)] strip_tags [去除html标签] truncate [截取] upper [大写] wordwrap [行宽约束]

使用变量调节器:

{foreach $goods as $key=>$g}

    {$g.goods_id}
    {$g.goods_name|truncate:15:'...'}
    {$g.shop_price}
    {$g.add_time|date_format:"%Y-%m-%d %H:%M:%S"}

{/foreach}

调节器的功能,在PHP中也能实现,也可以在模板中进行。比较合适在模板中进行。
体现了业务与显示的分离,尽量分离。

PHP就负责判断条件,并取出数据来。
至于显示的操作,应该尽量往"前"移(越接近用户).
MySQL-->PHP-->模板-->JavaScript

合适在MySQL存储原始数据,PHP中处理.
后台的数据尽量“原始”,不要带有样式,格式。显示的工作尽量靠前.

页面缓存

缓存,smarty重要概念。
缓存:把页面内容保存在磁盘上,下次访问相同页面,直接返回保存内容。减轻了数据库的压力。

smarty缓存的用法:

  1. 开启

  2. 配置缓存的生命周期

  3. 判断是否缓存成功并是否从数据库取出数据

  4. 输出

// 开启缓存 
$smarty->caching = true;

// 设置缓存生命周期
$smarty->cache_lifetime = 3600;

// 缓存的文件目录,用户存储缓存文件
$smarty->cache_dir = './cache';

if ( !$smarty->isCached('cache.html') ) { // 判断文件是否缓存

    // 链接数据库
    $conn = mysql_connect('127.0.0.1', 'root', '');
    
    // 设置字符集
    mysql_query('set names utf8', $conn);
    
    // 选择数据库
    mysql_query('use boolshop', $conn);
    
    // 查询数据
    $sql = "select goods_id, goods_name, shop_price, add_time from goods limit 5";
    
    $result = mysql_query($sql, $conn);
    $goods = array();
    while ( $row = mysql_fetch_assoc($result) ) {
        $goods[] = $row;
    }
    
    // 关闭数据库连接
    mysql_close($conn);
    
    // 赋值    
    $smarty->assign('goods', $goods);
    
    echo '走了数据库';
}    
    
    $smarty->display('cache.html');    

局部缓存

smarty在页面缓存的情况下,可以设置部分内容不缓存。页面中有随机广告,时间,股票信息,不适宜缓存起来。

运行的时候,还是PHP代码,没有生成静态数据。

控制局部不缓存:

  • 在标签中控制,该标签不缓存。

// {$标签 nocache}

{$time|date_format:"%Y-%m-%d %H:%M:%S" nocache}

  • 控制一段标签不缓存

{nocache}

{$time|date_format:"%Y-%m-%d %H:%M:%S"}

{$time|date_format:"%Y-%m-%d %H:%M:%S"}

{/nocache}
  • 在PHP赋值时,就控制不缓存

$smarty->assign('time2', $time, true); // 第三个参数是 nocache,为true,说明不缓存

不缓存标签,要保证总能从PHP处得到值.

  • 调用函数

定义函数

function insert_welcome( $parm ) {
    return 'WELCOME HELLO' . ', AGE:' . $parm['age']; 
}

模板中使用:

{insert name="welcome" age=21}

单模版多缓存

场景:为商品模板设置缓存,当时从url接收的goods_id,当缓存后,所有商品都一样了,不合适。

能否为同一个模板,生成不同的缓存文件呢?
比如:根据ID的不同,来生成各个商品的缓存页面。
可以使用:单模板多缓存,
原理:生成缓存的时候,可以再传一个缓存ID。如果ID不同,则生成缓存文件不同。

// 编译    
$smarty->display('one_page.html', $goods_id);    

一般的,哪些参数要影响页面的内容,就需要把哪些参数,当成“缓存ID”。
例如:分页:page=3, 栏目:cat_id=3

多个参数影响:

// 编译    
$one_page = $goods_id + $page;  // 缓存ID,根据自定义规则计算
$smarty->display('one_page.html', $one_page);    

// 缓存判断,也需要加缓存ID
if ( !$smarty->isCached('one_page'.html, $one_page) ) {
}

模板缓存:

caching = true;
    
    // 设置缓存生命周期
    $smarty->cache_lifetime = 10;
    
    // 缓存的文件目录,用户存储缓存文件
    $smarty->cache_dir = './cache';

         
    $goods_id = $_GET['goods_id'] + 0;
        
if ( !$smarty->isCached('one_page.html', $goods_id) ) {
            
    // 链接数据库
    $conn = mysql_connect('127.0.0.1', 'root', '');
    
    // 设置字符集
    mysql_query('set names utf8', $conn);
    
    // 选择数据库
    mysql_query('use boolshop', $conn);
    
    // 查询数据
    $sql = "select goods_name, shop_price, goods_desc from goods where goods_id=" . $goods_id;
    
    
    $result = mysql_query($sql, $conn);
    $goods = mysql_fetch_assoc($result);
    
    // 关闭数据库连接
    mysql_close($conn);
    
    // 赋值    
    $smarty->assign($goods);
    
}    

    // 编译    
    $smarty->display('one_page.html', $goods_id);    

?>

强制删除缓存

简单删除缓存.
指定模板名,不指定缓存ID,则该模板对应的缓存都会被删除.
可以通过缓存ID来控制,模板对应的指定缓存删除掉.

clearCache('one_page.html', $goods_id);
    
    echo '删除缓存成功';

?>

出于调试目的,临时不缓存文件

$smarty->force_cache = true; // 强迫文件不缓存

数据对象

作用:数据分类,添加命名空间

不使用数据对象,所有数据都存储在smarty对象中.(重名就覆盖)
数据对象:把数据分类(不同类别的数据,重名不会覆盖)

assign('nav', $nav_top);
    $smarty->assign('nav', $nav_footer);  // 数据覆盖
    
    /**
     * smarty3引入一种新的概念,叫做数据对象。
     * 数据对象,就是一个装数据用的框。
     * 
     * 靠2个数据对象,把2个数据对象里,各赋值一个同名的`nav`,2个`nav`对象互不干扰
     */
    
    $smarty->display('news.html');
    
?>

使用数据对象,命名空间

  1. 创建数据对象$smarty->createData();

  2. 数据挂载到该数据对象上.

  3. $smarty->dispaly();声明使用的数据

assign('nav', $nav_top);
//    $smarty->assign('nav', $nav_footer);
    
    /**
     * smarty3引入一种新的概念,叫做数据对象。
     * 数据对象,就是一个装数据用的框。
     * 
     * 靠2个数据对象,把2个数据对象里,各赋值一个同名的`nav`,2个`nav`对象互不干扰
     */
     
     
    // 创建一个数据对象
    $hdata = $smarty->createData();
    $fdata = $smarty->createData();

    // 使用数据对象
    $hdata->assign('nav', $nav_top);
    $fdata->assign('nav', $nav_footer);    
    
    // display时,要声明,这次使用,哪个数据对象。
    $smarty->display('header.html', $hdata);
    $smarty->display('news.html');
    $smarty->display('footer.html', $fdata);
    
?>

对象注册

场景:在模板中,smartty标签中,允许调用对象的方法,如果方法是特殊方法,比如修改密码等方法。(模板调用特殊方法)

使用对象注册的方式来解决。

作用:允许调用的方法列表。

在View视图中:
注册对象的 变量:访问方法{zf->name}. 注意不加$,方法后不加()

name;    
        }
        
        public function modPass() {
            return '修改密码成功';
        }
        
    }
    
    $zf = new User();
    
//    $smarty->assign('zf', $zf);

    // 对象注册
    $smarty->registerObject('zf', $zf, array('say')); // 第三个参数可以控制允许调用的方法.
    
    $smarty->display('objLogin.html');

?>



    
        
        
    
    
        
        

姓名:{zf->name}

年龄:{zf->age}

SAY:{zf->say}

{zf->modPass}

模板继承

可以在父模板中,暂留{block name=""}{/block}

注意:

  1. 子模板第一句,先声明继承{extends file=''}

  2. 子模板的目的,只是填充父模板预留的block

父模板:



    
        
        {block name='title'}父模板标题{/block}
    
    
        {block name='header'}{/block}
        
{block name='footer'}{/block}

子模板1:

{extends file='tplExteds.html'}
{block name="title"}
  • 嘻嘻哈哈
  • 嘻嘻
  • 哈哈
{/block} {block name="header"}头部{/block}

子模板2:

{extends file='tplExted.html'}
{block name="footer"}2016年最后二天{/block}

变量调节器插件开发

调节器:

' . $string . '';
    }
    
?>
  1. 在smarty源码的目录中,plugins, 开发。

  2. 文件命名modifier.函数名.php

  3. 定义的调节器的函数名:Smarty_modifier_modcolor

display与fetch

display() 可以看成 echo fetch();
fecth()仅仅计算出应输出的结果,但是不输出,只把结果返回。

PHP_Smarty_第1张图片

一个PHP页面如何知道本身的输出结果: 使用缓冲区

利用fetch静态化

缓冲区的理解:

PHP_Smarty_第2张图片

fetch是如何知道当前页面的输出内容?
输出到缓冲区,在PHP的最后,读取缓冲区,就是本页面的内容。

打开缓冲区:ob_start();
读取缓冲区:ob_get_content();
清空缓冲区:ob_clean();
读取并清空:ob_get_clenan();

静态化:缓冲区+文件写操作

模板引擎特点

所有模板的共性:解析标签,解析成PHP

标签解析的分类:

  1. 最多的就是正则替换 。 例如:smarty2.X系列,quickskin

  2. 通过字符串函数来解析 例如:dede的模板类.

字符串解析

right_length = strlen($this->right_delimiter);
        }
         
        protected $tags = array(); // 装载分析到的标签 
         
        // 编译
        public function parse( $file ) {
            $cont = file_get_contents('./templates/' . $file);
            
            $offset = 0;
            // 截取第一个字符 '{'
            while ( $poss = strpos($cont, $this->left_delimiter, $offset) !== false ) {
                // 取最后字符 '}'
                $pose = strpos($cont, $this->right_delimiter, $poss);
                
                // 截取标签
                $this->tags[] = substr($cont, $poss, $pose-$poss+$this->right_length);
                
                $offset = $pose + $this->right_length; 
                
            }
            return $this->tags;
        }
    }
?>

变量的存储分类:

  1. 最多的是通过assign,把变量再次装载到模板对象中。
    如:smarty,thinkphp

  2. 只把模板解析出来,再包含模板
    如:discuzd的模板,把模板解析后,只返回模板的路径,再手动包含。(省略了assign过程,速度更快,显示的粗糙暴力)

语言分类:

  1. 绝大部分PHP

  2. C语言以扩展形式写的模板引擎(Blitz)

你可能感兴趣的:(模板引擎,模板,smarty,php)