框架模版系统采用二次编译模式,严格实现模板与程序的分离,通过通俗的标签模式调用各类数据。基本模板格式简单易学,方便制作,只要对HTML有一定了解就可以很快上手,模板修改后即时生效。同时具备高度可扩展性,可根据实际需要任意扩充模版标签。
实例声明
模版类的实例创建代码如下:
$tpl = new myTemplate($tpl_setting, $tpl_cache, $allow_script, $delimiter);
参数一 $tpl_setting 为调用设置,为一个字符串下标的数组,包括以下参数:
- name - 必选项,所调用的模版文件名;
- path - 必选项,模版文件存放的路径;
- style - 可选项,模版样式名,即模版目录下的子目录名,默认为空;
- path_compile - 可选项,编译文件存放的路径,默认为模版目录下的 comipled 子目录;
- ext - 可选项,模版文件的扩展名,默认为 tpl;
参数二 $tpl_cache 为缓存设置,也就是将生成的页面作为缓存保存至文件,如为 false 则表示不使用缓存,否则为一个字符串下标的数组,包括以下参数:
- name - 缓存文件名,默认为模版文件名,在同一模版生成不同页面时(如文章内容页)设置;
- path - 缓存路径,默认为模版目录下的 cache 子目录;
- ext - 缓存文件的扩展名,默认为 html;
- expire - 缓存过期时间,单位为秒,默认为 300。
参数三 $allow_script 为布尔值,表示是否允许在模版代码中加带 PHP 代码。
参数四 $delimiter 为间隔符,用于划分模版变量的标识符,框架默认的标识符设置为:左标识符 <!-- 和右标识符 --> ,即 ['<!--', '-->']。
模版语法
赋值语法
1、单变量赋值
模版语法:<!--name-->
赋值方式:$tpl->assign('name', 'value');
结果:对应的模版标签将被替换为 value 。
2、多变量赋值
模版语法:<!--name_1-->、<!--name_2-->、<!--name_3-->(相关标签可以在模版的任意位置)
赋值方式:
$tpl->assign([
'name_1'=>'value_1',
'name_2'=>'value_2',
'name_3'=>'value_3',
]);
结果:将依次将对应数组下标的标签替换为对应的值。
3、多变量带前缀赋值
模版语法:<!--pre_name_1-->、<!--pre_name_2-->、<!--pre_name_3-->(相关标签可以在模版的任意位置)
赋值方式:
$tpl->assign('pre', [
'name_1'=>'value_1',
'name_2'=>'value_2',
'name_3'=>'value_3',
]);
结果:将依次将数组下标添加前缀,并将前缀标签替换为对应的值。
4、多变量文件赋值
模版语法:同以上三种模式
赋值方式:$tpl->loadSet($file, $prefix, $mode)
-
- $file - 变量文件,格式可以为 ini,php(返回字符串下标的数组) 或 json ,支持多级递归;
- $prefix - 对应 assign 方法中,对变量前缀赋值模式中的前缀;
- $mode - 递归数组标签命名方式,设定为 false 的话,则只取当前下标作为标签名,否则按照变量深度,依次将各级数组下标用“_”连接作为标签名。
结果:参考多变量赋值
循环语法
模版语法:
<ul>
<!--loop:start key="info" time="5"-->
<li><a href="<!--info_url-->" title="<!--info_comment-->" target="_blank"><!--info_name--></a></li>
<!--loop:end-->
</ul>
模版循环标签通过 loop:start 和 loop:end 标签将循环部分包起,标签内含有两个属性,key属性为必选项,相当于赋值前缀,目的是为了区分循环变量和普通变量;time属性为可选项,表示最低循环次数,也就是在赋值数量不足这个数字时,将再加上几个空的项目以达到规定数额(保证页面布局整齐)。
赋值方式:$tpl->setLoop($key, $data, $fullset)
-
- $key 为索引值,对应模版中的 key 属性;
- $data 为数据项,用于依次将数据循环赋值给模版;
- $fullset 注明数据项是否为全套数据,默认为false。
一次性将所有数据提交:
$record = array(
['url'=>'###', 'comment'=>'text1', 'name'=>'name1'],
['url'=>'###', 'comment'=>'text2', 'name'=>'name2'],
['url'=>'###', 'comment'=>'text3', 'name'=>'name3'],
['url'=>'###', 'comment'=>'text4', 'name'=>'name4'],
);
$tpl->setLoop('info', $record, true);
通过循环按组提交:
$record = array(
['url'=>'###', 'comment'=>'text', 'name'=>'name'],
['url'=>'###', 'comment'=>'text', 'name'=>'name'],
['url'=>'###', 'comment'=>'text', 'name'=>'name'],
['url'=>'###', 'comment'=>'text', 'name'=>'name'],
);
while($data=next($record)) {
$tpl->setLoop('info', $data);
}
上例通过循环依次将每一组变量赋值到循环标签中,本方法多用于数据结果集的依次读取并赋值。
判断语法
模版语法:(其中 else 部分不是必须的)
<!--if:start key='error'-->
<p style="color:red;">No!!!!</p>
<!--else-->
<p style="color:green;">Yes</p>
<!--if:end-->
赋值方式:$tpl->setIf($key, $value)
-
- $key 为索引值,对应模版中的 key 属性;
- $value 为布尔值,用于对标签做判断。
$tpl->setIf('error', $flag)
上例中,如果 flag 为 true ,则显示标签上半部分;否则显示下半部分,如无下半部分则不显示内容。
结构选择
模版语法:
<!--switch:start key='in_the_box'-->
<!--(1)-->
<p>It's an apple.</p>
<!--(2)-->
<p>It's a dog.</p>
<!--(3)-->
<p>Nothing here!</p>
<!--switch:end-->
赋值方式:$tpl->setSwitch($key, $value)
-
- $key 为索引值,对应模版中的 key 属性;
- $value 为判断值,对比各子部分的索引值,如相同则显示其下面的内容。
$tpl->->setSwitch('in_the_box', rand(1, 3));
随机选择
模版语法:
<!--random:start-->
<p>aaa</p>
<!--(s)-->
<p>bbb</p>
<!--(s)-->
<p>ccc</p>
<!--random:end-->
本标签随机显示被 <!--(s)--> 间隔的项目之一,无属性,无赋值。
扩展标签
本模版系统可以通过扩展标签实现更多自如、复杂的组合。扩展标签也可称为块模版一般为单一功能(如循环、判断、选择或纯静态)但是会在页面反复用到的页面功能块,依照传入参数的不同,依照相同的机理显示不同的内容。例如不同栏目的新闻列表(循环),登陆模块(静态),用户信息显示(判断),页面功能(选择)等。
模版语法
格式:<!--tag name1='value1' name2='value2'-->
-
- tag 为自定义的标签名称
- name1、name2 为属性名称,可根据标签需要设定无限多个;
- value1、value2 为属性值,既可以为具体的数字或字符串,也可以为变量名称,但需要注意的是此变量必须为全局变量,如 name1='$_GET["c"]' 或 name2="$var"。
- 需要注意的是如果属性值为变量,则该变量需要在对应的解析脚本中做全局化声明,如上例中的name2的值为 $var,需要在解析脚本头部加上 global $var
解析方法
代码:$tpl->regTag($tag_name, $tag_func)
-
- $tag_name 为标签名称,对应上文中的 tag;
- $tag_func 为解析函数,可为任意有效的函数调用名称,或者闭包函数,此函数会被传入两个参数,参数一为当前模版实例,参数二为解析好的标签属性数组,如模版语法示例的标签对应属性的参数为:array('name1'=>'value1', 'name2'=>'value2'),此参数为址传递,可在解析函数中扩种内容,以供模版解析调用。
模版语法
与主模版语法类似,标签模版可通过标签属性传递相关参数,省去了主模版语法中的属性设置,且只包含 loop、if、switch 三种结构。
解析函数
由于涉及到了模版解析,需要用到模版类内部的两个方法:
-
- $tpl->getTemplate($file) ,本方法将返回自定义标签所对应的块模版文件内容;
- $tpl->getBlock($tpl_content, $tag, $idx),本方法将从自定义块模版文件中解析出所需的功能结构,各函数意义如下:
- $tpl_content - 块模版文件内容;
- $tag - 需要解析的功能结构名,即 loop、if、switch;
- $idx - 仅作用于 loop 结构,相当于循环数据标识的前缀。
本方法将返回一个包含三个项目的数组,如下:- 0 - 整体功能结构的代码
- 1 - 单元代码,loop结构返回需要循环的代码;if结构返回判断为 true ,即 else 前面的代码;switch结构返回以符合值为下标,值为对应代码的数组
- 2 - 附加代码,loop结构返回不含模版标签的空行代码(即去掉单元代码所有模版变量标签后的部分);if结构返回判断为 false ,即 else 后面的代码;switch结构返回空字符串
下面将以一个实例来演示扩展标签的使用方法,首先我们先设置一个自定义标签:
<!--test name='$_get["n"]' author="myStep" time='Y-m-d' loop='5'-->
需要注意的是,有两个属性名称是不可使用的,分别是 unit 和 unit_blank ,分别对应块模版功能结构中的结构内代码(即被定界符包起来的部分)和loop结构中的空行代码(即去掉unit代码中所有模版变量标签后的部分)。
对应的块模版文件:
<ul>
<li><!--name--> - <!--author--></li>
<!--loop:start-->
<li style="<!--news_style-->">
<em><!--news_catalog--></em>
<a href="<!--news_link-->" title="<!--news_subject-->" target="_blank"><!--news_subject--></a>
<i><!--news_add_date--></i>
</li>
<!--loop:end-->
</ul>
解析代码如下:
$tpl->regTag('test', 'parseTest');
function parseTest(myTemplate &$tpl, &$att_list = array()){
$tpl_content = $tpl->getTemplate('path/template/block_loop.tpl');
list($block, $att_list['unit'], $att_list['unit_blank'])= $tpl->getBlock($tpl_content, 'loop', 'news');
$result = <<<'mytpl'
<?PHP
$result = array(
['style'=>'style', 'catalog'=>'catalog', 'link'=>'###', 'subject'=>'subject', 'add_date'=>'0'],
['style'=>'style', 'catalog'=>'catalog', 'link'=>'###', 'subject'=>'subject', 'add_date'=>'0'],
['style'=>'style', 'catalog'=>'catalog', 'link'=>'###', 'subject'=>'subject', 'add_date'=>'0'],
);
$n = 0;
foreach($result as $news) {
$news['add_date'] = date('{myTemplate::time}', $news['add_date']);
echo <<<content
{myTemplate::unit}
content;
if(++$n >= {myTemplate::loop}) break;
}
for(; $n<{myTemplate::loop}; $n++) {
echo <<<content
{myTemplate::unit_blank}
content;
}
?>
mytpl;
return str_replace($block, $result, $tpl_content);
}
首先,通过 regTag 的方法注册 parseTest 方法用于解析 test 标签,再通过解析方法,将对应的标签转换为php脚本,大致流程为:
-
- 通过 getTemplate 方法获取对应模块模版文件代码;
- 通过 getBlock 方法获取指定功能结构的相关代码,具体内容见上
- 获取数据,并转换模版代码为php代码,其中如果解析出的代码需要用到属性代码,由于此代码可能是变量,可以通过 {myTemplate::属性名称} 的方式插入到代码里,框架系统将在最后编译时替换为对应的变量或固定值,此外对于子模版中的单变量赋值标签,框架系统将会自动寻找同名属性值替换,如上例中的 name 被替换为 $_GET['n'],author 被替换为 myStep。
- 在将相关代码转换为对应的PHP代码后,将原有标签结构部分替换为所解析的PHP代码,并返回结果。当然,返回内容视标签具体情况而定,可灵活掌握。
页面生成
页面生成
生成页面的方法为:$tpl->render($global_vars, $tpl_show, $minify)
-
- $global_vars 对于编译后的模版,由于属于黑盒执行的php脚本,相关全局变量需要通过此变量进行声明,内容为以逗号间隔的变量名;
- $tpl_show 是否直接用于显示,默认为true,如果为false的话将直接返回编译后的页面内容;
- $minify 是否对生成的页面内容做压缩处理,默认为false
本方法为模版类最后的实现方法,在解析之前框架系统会自动判断是否存在编译缓存,如存在且未过期,同时模版文件更改日期早于编译文件生成日期,则直接调用已编译好的缓存文件。
子模版引入
本模版系统未设置子模版的引入机制,但是可以通过声明子模版实例,再将解析后的页面代码(子模版实例的 $tpl_show 设定为 false)直接赋值给主模版的单一变量标签即可实现相同的结果,相关内容也更为可控。