<?php
//呵呵,我的英文不是很好,下面很多注释不一定正确,懂英文的就自已看英文注释吧,也许更容易看懂
class Template_class
{
/**
* When is set to true it makes the class clean the loops and cloops data
* The value of this variable can be set while creating the object 当创建对象的时候,这个变量的值可以被设置
*
* @var bool
* @access public
*/
var $reset = TRUE;
/**
* The beginning of the normal tags
*
* @var string
* @access public
*/
var $ldelim = '{'; //正规标签始端
/**
* The end of the normal tags
*
* @var string
* @access public
*/
var $rdelim = '}';//正规标签末端
/**
* The beginning of the opening tag for blocks
*
* @var string
* @access public
*/
var $BAldelim = '{';//开始标签始端
/**
* The end of the opening tag for blocks
*
* @var string
* @access public
*/
var $BArdelim = '}';//开始标签末端
/**
* The beginning of the closing tag for blocks
*
* @var string
* @access public
*/
var $EAldelim = '{/';//结束标签始端
/**
* The end of the closing tag for blocks
*
* @var string
* @access public
*/
var $EArdelim = '}'; //结束标签末端
/**
* Array containing the data for the tag: tags
*
* @var array
* @access private
*/
var $_scalars = array();//tag:标签 数组
/**
* Array containing the data for the loop: tags
*
* @var array
* @access private
*/
var $_arrays = array();//loop:标签 数组
/**
* Array containing the information about which array tags
* should be enabled for if: tags and which elements should be used
* since trying to find ifs for each array element and
* for each array entry would take a lot of time.
*
* @var array
* @access private
*/
var $_arrays_ifs = array();
/**
* Array containing the data for the cloop: tags
*
* @var array
* @access private
*/
var $_carrays = array();//cloop:标签 数组
/**
* Array containing the data for the if: tags
*
* @var array
* @access private
*/
var $_ifs = array();//if:标签 数组
/**
* Array containing the information of the plugins to be loaded
*
* @var array
* @access private
* @see $this->add_plugin
*/
var $_plugins = array();
/**
* Object constructor, set $reset to reset the arrays after processing 对象构造,设置$reset变量在处理后重新初始化数组
*
* @access public
* @param bool $reset
* @return Template_class
*/
function Template_class($reset = TRUE)
{
$this->reset = $reset;
}
/**
* Set a tag with a value, $var can be a string or an array 设置一个标签和一个值,$var变量可以是一个字符串或者一个数组
* Set $if to true if you want to be able to use that tag with if: conditions
*
* @param string $tag
* @param mixed $var
* @param bool $if
*/
function set($tag, $var, $if = NULL)
{
if(is_array($var))
{
$this->_arrays[$tag] = $var;
if($if!==null)
{
if(!is_array($if))
{
$result = $var ? TRUE : FALSE;
$this->_ifs[] = $tag;
$this->_scalars[$tag] = $result;
}
else
{
$result = $var ? TRUE : FALSE;
$this->_ifs[] = $tag;
$this->_scalars[$tag] = $result;
$this->_arrays_ifs[$tag]=$if;
}
}
}
else
{
$this->_scalars[$tag] = $var;
if($if) $this->_ifs[] = $tag;
}
}
/**
* Sets a case loop
*
* @access public
* @param string $tag The tag name
* @param array $array The array containing the data
* @param array $cases The array telling about the cases that it should check for
*/
function set_cloop($tag, $array, $cases)
{
$this->_carrays[$tag] = array(
'array' => $array,
'cases' => $cases);
}
/**
* Reset the template variables 重设模板变量
*
* @access public
* @param bool $scalars If the scalars data should be cleaned
* @param bool $arrays If the arrays data should be cleaned
* @param bool $arrays_ifs If the arrays_ifs data should be cleaned
* @param bool $carrays If the case arrays data should be cleaned
* @param bool $ifs If the ifs data should be cleaned
* @param bool $plugins If the plugins data should be cleaned
*/
function reset($scalars=false, $arrays=false, $arrays_ifs=false, $carrays=false, $ifs=false,$plugins=false)
{
if($scalars) $this->_scalars = array();
if($arrays) $this->_arrays = array();
if($arrays_ifs) $this->_arrays_ifs = array();
if($carrays) $this->_carrays = array();
if($ifs) $this->_ifs = array();
if($plugins) $this->_plugins = array();
}
/**
* Formats the tags & returns a two-element array, 格式化标签并且返回一个两个元素的数组
* the opening and closing tags 开始与结束标签
*
* @access public
* @param string $tag The tag name
* @param string $directive The directive name
* @return array
*/
function get_tags($tag, $directive)
{
$tags['b'] = $this->BAldelim . $directive . ':' . $tag . $this->BArdelim; //如{
$tags['e'] = $this->EAldelim . $directive . ':' . $tag . $this->EArdelim;
return $tags;
}
/**
* Formats a simple tag
*
* @access public
* @param string $tag The tag name
* @param string $directive The tag directive
* @return string The formated tag
*/
function get_tag($tag,$directive='tag')
{
return $this->ldelim . $directive . ':' . $tag . $this->rdelim;
}
/**
* Extracts a portion of a template( or a string) according to the
* opening ($tags['b']) and closing ($tags['e']) tags
*
* @param array $tags The opening and closing tags/delimeters
* @param string $contents The content from where it is going to extract
* @return string The extracted content
*/
function get_statement($tags, $contents)
{
// Locate the statement
$tag_length = strlen($tags['b']);
$fpos = $tags['b']===null? 0 : strpos($contents, $tags['b']);
$lpos = $tags['e']===null? strlen($contents) : strpos($contents, $tags['e']);
if($fpos===false||$lpos===false)
return false;
$fpos += $tag_length;
$length = $lpos - $fpos;
// Extract & return the statement
return substr($contents, $fpos, $length);
}
/**
* Parse the template with the variables 解析模板变量
*
* @access public
* @param string $contents The template
* @return string The parsed template
*/
function parse($contents)
{
/**
* Process the ifs (if any)
*/
foreach($this->_ifs as $value)
{
$contents = $this->_parse_if($value, $contents);
}
/**
* Process the scalars (if any)
*/
foreach($this->_scalars as $key => $value)
{
$contents = str_replace($this->get_tag($key), $value, $contents);
}
/**
* Process the arrays (if any)
*/
foreach($this->_arrays as $key => $array)
{
$contents = $this->_parse_loop($key, $array, $contents);
}
/**
* Process the case arrays (if any)
*/
foreach($this->_carrays as $key => $array)
{
$contents = $this->_parse_cloop($key, $array, $contents);
}
$plugins_count=count($this->_plugins);
/**
* Process the plugins (if any)
*/
for ($n=0;$n<$plugins_count;$n++)
{
if($this->_plugins[$n]['object']===null)
$obj=new $this->_plugins[$n]['function']();
else
$obj=&$this->_plugins[$n]['object'];
//
//Now we check what protocol version the plugin was designed for
//
switch ($obj->version('protocol'))
{
case "1.0":
{
//
//Now we give the object itself to the function, so it can access the current settings
//
$contents=$obj->parse($contents,$this);
}break;
}
}
/**
* Reset the data according to the settings
*/
if($this->reset) $this->reset(FALSE, TRUE, TRUE, TRUE);
return $contents;
}
/**
* Parses an if statement //解析一个if...esle...语句,示例:{if:标签}...{else:标签}...{/if:标签}
*
* @access private
* @param string $tag The tag name
* @param string $contents The current as-processed template
* @param string $replace If the function should consider as $replace without checking the real value
* @return string The parsed template
*/
function _parse_if($tag, $contents, $replace=null)
{
//
// Get the tags
//
$t = $this->get_tags($tag, 'if'); //返回一个$t数组,值分别为:$t['b']="{if:标签$tag}",$t['e']="{/if:标签$tag}",如:{if:test}{/if:test}
//
//We loop this so we can process all the ifs for this tag
//
while (($entire_statement = $this->get_statement($t, $contents))!==false)
{
// Get the else tag 获取else标签
$tags['b'] = NULL;
$tags['e'] = $this->get_tag($tag, 'else');
// See if there's an else statement 判断是否有else语句
if(($else = strpos($entire_statement, $tags['e'])))
{
// Get the if statement
$if = $this->get_statement($tags, $entire_statement);
// Get the else statement
$else = substr($entire_statement, $else + strlen($tags['e']));
}
else
{
$else = NULL;
$if = $entire_statement;
}
//
//If the function wasn't called with a value for $replace we check the _scalars array
//
if($replace===null||!is_bool($replace))
$replace=!empty($this->_scalars[$tag])?true:false;
//
//If the condition is valid then we use the 'if' (first) part, if not, then we use 'else'
//
$replace=($replace) ? $if : $else;
//
// Parse the template
//
$contents = str_replace($t['b'] . $entire_statement . $t['e'], $replace, $contents);
}
//
//Return the template
//
return $contents;
}
/**
* Parses a loop //解析一个loop语句,示例:{loop:标签}...{/loop:标签}
*
* @access private
* @param string $tag Tag name
* @param array $array The array containing the loop data
* @param string $contents The current as-processed template
* @return string The parsed template
*/
function _parse_loop($tag, $array, $contents)
{
// Get the tags & loop
$t = $this->get_tags($tag, 'loop');
while (($loop = $this->get_statement($t, $contents))!==false)
{
$parsed = NULL;
$if_key_exists=isset($this->_arrays_ifs[$tag]);
// Process the loop
foreach($array as $key => $value)
{
/**
* We create a copy of the loop so we can keep the original loop
* but work on this one
*/
$i = $loop;
if($if_key_exists&&isset($this->_arrays_ifs[$tag][$key]))
$i=$this->_parse_if($tag . '.' . $key,$i,!empty($value)?true:false);
/**
* array(1=>array('key_name'=>'value','some_key'=>'value'))
* {tag:tag_name[].key_name},{tag:tag_name[].some_key}
* {tag:tag_name[].key_name[]},{tag:tag_name[].some_key[].some_subkey}
*/
if(is_numeric($key) && is_array($value))
{
foreach($value as $key2 => $value2)
{
if($if_key_exists&&isset($this->_arrays_ifs[$tag][$key2]))
$i=$this->_parse_if($tag . '[].' . $key2,$i,!empty($value2)?true:false);
if(!is_array($value2))
{
// Replace associative array tags
$i = str_replace($this->get_tag($tag . '[].' . $key2), $value2, $i);
}
else
{
// Check to see if it's a nested loop
$i = $this->_parse_loop($tag . '[].' . $key2, $value2, $i);
}
}
}
/**
* array('tsgsgs'=>'sgsgdgg')
* {tag:tag_name.key_name}
*/
elseif(is_string($key) && !is_array($value))
{
$i = str_replace($this->get_tag($tag . '.' . $key), $value, $i);
}
/**
* array(1=>'fff')
* {tag:tag_name[]}
*/
elseif(!is_array($value))
{
$i = str_replace($this->get_tag($tag . '[]'), $value, $i);
}
// Add the parsed iteration
if(isset($i)) $parsed .= rtrim($i);
}
//
// Parse the template
//
$contents=str_replace($t['b'] . $loop . $t['e'], $parsed, $contents);
}
//
//Return the template
//
return $contents;
}
/**
* Parse a case loop 解析一个case循环语句,相当于switch一样
*
* @access private
* @param string $tag The tag name that is going to be parsed
* @param array $array Array with the loop elements
* @param string $contents The current as-processed template
* @return string The parsed template
*/
function _parse_cloop($tag, $array, $contents)
{
// Get the tags & loop
$t = $this->get_tags($tag, 'cloop'); //返回{cloop:名称}{case:名称}...{default:名称}{/cloop:名称}
while (($loop = $this->get_statement($t, $contents))!==false)
{
// Set up the cases
$array['cases'][] = 'default';
$case_content = array();
$parsed = NULL;
// Get the case strings
foreach($array['cases'] as $case)
{
$ctags[$case] = $this->get_tags($case, 'case');
$case_content[$case] = $this->get_statement($ctags[$case], $loop);
}
// Process the loop
foreach($array['array'] as $key => $value)
{
if(is_numeric($key) && is_array($value))
{
// Set up the cases
if(isset($value['case'])) $current_case = $value['case'];
else $current_case = 'default';
unset($value['case']);
$i = $case_content[$current_case];
// Loop through each value
foreach($value as $key2 => $value2) {
$i = str_replace($this->get_tag($tag . '[].' . $key2), $value2, $i);
}
}
// Add the parsed iteration
$parsed .= rtrim($i);
}
// Parse & return the final loop
$contents=str_replace($t['b'] . $loop . $t['e'], $parsed, $contents);
}
return $contents;
}
/**
* Parses the file $file_name as a template
*
* @access public
* @param string $file The template file name
* @return string The processed template
*/
function fetch($file,$filename = '')
{
// Open the file
$fp = fopen($file, 'rb');
if(!$fp) return FALSE;
// Read the file
$contents = fread($fp, filesize($file));
// Close the file
fclose($fp);
// Parse and return the contents
if (empty($filename)){
/*------------------------------------*/
//动态浏览
return $this->parse($contents);
/*------------------------------------*/
}else{
/*------------------------------------*/
//生成静态页面
$content = $this->parse($contents);
$handle = fopen ($filename,"w"); //打开文件指针,创建文件
/*
检查文件是否被创建且可写
*/
if (!is_writable ($filename)){
//die ("文件:".$filename."不可写,请检查其属性后重试!");
}
if (!fwrite ($handle,$content)){ //将信息写入文件
//die ("生成文件".$filename."失败!");
}
fclose ($handle); //关闭指针
/*------------------------------------*/
}
}
/**
* Works the same way as set() excepting that if the tag already exists //除了if标签已经存在以外,功能与set()一样
* it doesn't replaces it, it appends the new value (if it is an string)
* or it merges the content (if it is an array). //append()不能代替set(),append() 添加一个新值(如果这个值是一个字符串),或者添加一个元素(如果它是一个数组)
* Please note that this function will not make any change
* to the array_ifs data, to update that information,//请注意这个函数对array_ifs数据更新信息不会产生任何改变
* set() has to be used instead //set()函数则一定会替换旧的值
*
* @param string $tag
* @param mixed $var
* @param bool $if
*/
function append($tag, $var, $if = NULL)
{
if(is_array($var))
{
if(!isset($this->_arrays[$tag]))
$this->_arrays[$tag]= $var;
else
$this->_arrays[$tag]=array_merge($this->_arrays[$tag],$var);
if($if)
{
$result = $var ? TRUE : FALSE;
$this->_ifs[] = $tag;
$this->_scalars[$tag] = $result;
}
}
else
{
if(!isset($this->_scalars[$tag]))
$this->_scalars[$tag] = $var;
else
$this->_scalars[$tag] .= $var;
if($if) $this->_ifs[] = $tag;
}
}
/**
* Adds a plugin to be called when a template is being parsed
* The $plugin_name is the name of the class which is the plugin
*
* The $setup var may contain any type of data, because it is pased directly to the $plugin_name::setup() function of the plugin class
* The arguments passed to the $plugin_name::parse() function will be $contents and the object itself ($this), in that order, and the function will only return the parsed template.
*
* The $plugin_name::setup() function may return an array with some settings
*
* Notes:
* The plugin class must have the next functions, which are going to be called by the template engine:
* -$plugin_name::setup() This function can be used to setup either the template engine when calling the plugin or to setup the plugin itself, in the last case, the $setup param can be used to give some settings to the plugin
* -$plugin_name::parse() This function is called when the class 'executes' the plugin
* -$plugin_name::version() This function must have one argument, which specifies the version of what is being requested: 'protocol' is the current plugins protocol, for the current version is 1.0; 'plugin' is the plugin version, it can be useful to debug
*
* @access public
* @param string $plugin_name The name of the function or class to be called
* @param mixed $setup Special settings that can be given to the plugin
*/
function add_plugin($plugin_name,$setup=null)
{
$n=count($this->_plugins);
$this->_plugins[$n]['function']=$plugin_name;
$this->_plugins[$n]['setup']=$setup;
$obj=new $plugin_name();
$this->_plugins[$n]=array_merge($this->_plugins[$n],$obj->setup($setup));
if (!isset($this->_plugins[$n]['refresh_object'])||$this->_plugins[$n]['refresh_object']===false)
$this->_plugins[$n]['object']=&$obj;
else
$this->_plugins[$n]['object']=null;
}
}
?>
=================================
示例
=================================
将以上代码保存到Template_class.php文件中.看不看得懂并不重要,只要看懂以下代码学会用就可以了,以下主要的代码我都加在后面******号,其它的代码可有可无,自已写就得了,灵活运用
--------------------------------
调用类的测试页 test.php 相关代码
--------------------------------
<?php
include ("conn.php");//创建数据库链接
include ("mysql_func.php");//自定义的一个数据库处理页面
require_once("Template_class.php");//******这是上面的模板处理类页面
$tpl=new Template_class();//******创建对象
$sql = "select * from test ";
genpage($sql,15);//这是一个分页函数,具体代码在mysql_func.php里,统计总页数,并返回一个$sql语句,以便下面这行使用,15为每页显示的记录数
$result = mysql_query($sql);
while($rs =mysql_fetch_array($result))
{
$test[] = array("str"=>"$rs[str]");//******这个数组的名称很重要,也可以自定义,但要与下面set里的参数$test名称相同,最好三个参数的名称都一样,如下面的test,如果页面里不用显示数据列表的话,此数组可省略,str为数据库表里的一个字段名称
//上面这里只以显示一个字段为例,如果有多个字段则$test[] = array("str"=>"$rs[str]","字段名称"=>"值",...);
}
//******以下set()函数比较重要,主要是将模板面里的相关标签替换为相关值,$tpl->set("标签名称","要替换的值");
$tpl->set("test",$test,array("test"=>true));//将数据替换到静态模板页相关位置,注意后面的array("test"=>true)这个参数,一般是显示数据列表时用到
$tpl->set("showpage",showpage());//******将分页代码插入静态模板页的指定位置
$tpl->set("title","测试调用模板处理类");//******如果只是一个字符串的话,可以这样子
//...根据模板页面设置好的标签多少在此增加或减少$tpl->set()
die($tpl->fetch("mode.html"));//******将数据填充入静态模板页mode.html并直接显示出来,不生成静态页面
//如果需要生成静态页面的话,那么上一句这样写即可,die($tpl->fetch("模板页的路径及名称","要生成页面的路径及名称"));如die($tpl->fetch("mode.html","/1/1.html"));
?>
--------------------------------
静态模板页 mode.html 相关代码
--------------------------------
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
</head>
<body>
<table>
<tr><td>{tag:title}<!--这里就是上面那个tpl->set("title","测试调用模板处理类");要替换的位置--></td></tr>
<!--下面开始循环显示记录,下面的那个:号左边的标签test可以改变,但要对应正确-->
{if:test}
{loop:test}
<tr>
<td align="center">{tag:test[].str}</td>
<!--
如果有更多字段的话
<td align="center">{tag:test[].str2}</td>
<td align="center">{tag:test[].str3}</td>
...
-->
</tr>
{/loop:test}
{else:test}
<tr>
<td height="100" align="center">没有数据</td>
</tr>
{/if:test}
</table>
<table width="100%" border="0" cellpadding="0" cellspacing="0">
<tr>
<td>{tag:showpage}<!--这里是分页处--></td>
</tr>
</table>
</body>
</html>
ok,就说到这了,其它的就自已去研究与测试吧,呵呵
//呵呵,我的英文不是很好,下面很多注释不一定正确,懂英文的就自已看英文注释吧,也许更容易看懂
class Template_class
{
/**
* When is set to true it makes the class clean the loops and cloops data
* The value of this variable can be set while creating the object 当创建对象的时候,这个变量的值可以被设置
*
* @var bool
* @access public
*/
var $reset = TRUE;
/**
* The beginning of the normal tags
*
* @var string
* @access public
*/
var $ldelim = '{'; //正规标签始端
/**
* The end of the normal tags
*
* @var string
* @access public
*/
var $rdelim = '}';//正规标签末端
/**
* The beginning of the opening tag for blocks
*
* @var string
* @access public
*/
var $BAldelim = '{';//开始标签始端
/**
* The end of the opening tag for blocks
*
* @var string
* @access public
*/
var $BArdelim = '}';//开始标签末端
/**
* The beginning of the closing tag for blocks
*
* @var string
* @access public
*/
var $EAldelim = '{/';//结束标签始端
/**
* The end of the closing tag for blocks
*
* @var string
* @access public
*/
var $EArdelim = '}'; //结束标签末端
/**
* Array containing the data for the tag: tags
*
* @var array
* @access private
*/
var $_scalars = array();//tag:标签 数组
/**
* Array containing the data for the loop: tags
*
* @var array
* @access private
*/
var $_arrays = array();//loop:标签 数组
/**
* Array containing the information about which array tags
* should be enabled for if: tags and which elements should be used
* since trying to find ifs for each array element and
* for each array entry would take a lot of time.
*
* @var array
* @access private
*/
var $_arrays_ifs = array();
/**
* Array containing the data for the cloop: tags
*
* @var array
* @access private
*/
var $_carrays = array();//cloop:标签 数组
/**
* Array containing the data for the if: tags
*
* @var array
* @access private
*/
var $_ifs = array();//if:标签 数组
/**
* Array containing the information of the plugins to be loaded
*
* @var array
* @access private
* @see $this->add_plugin
*/
var $_plugins = array();
/**
* Object constructor, set $reset to reset the arrays after processing 对象构造,设置$reset变量在处理后重新初始化数组
*
* @access public
* @param bool $reset
* @return Template_class
*/
function Template_class($reset = TRUE)
{
$this->reset = $reset;
}
/**
* Set a tag with a value, $var can be a string or an array 设置一个标签和一个值,$var变量可以是一个字符串或者一个数组
* Set $if to true if you want to be able to use that tag with if: conditions
*
* @param string $tag
* @param mixed $var
* @param bool $if
*/
function set($tag, $var, $if = NULL)
{
if(is_array($var))
{
$this->_arrays[$tag] = $var;
if($if!==null)
{
if(!is_array($if))
{
$result = $var ? TRUE : FALSE;
$this->_ifs[] = $tag;
$this->_scalars[$tag] = $result;
}
else
{
$result = $var ? TRUE : FALSE;
$this->_ifs[] = $tag;
$this->_scalars[$tag] = $result;
$this->_arrays_ifs[$tag]=$if;
}
}
}
else
{
$this->_scalars[$tag] = $var;
if($if) $this->_ifs[] = $tag;
}
}
/**
* Sets a case loop
*
* @access public
* @param string $tag The tag name
* @param array $array The array containing the data
* @param array $cases The array telling about the cases that it should check for
*/
function set_cloop($tag, $array, $cases)
{
$this->_carrays[$tag] = array(
'array' => $array,
'cases' => $cases);
}
/**
* Reset the template variables 重设模板变量
*
* @access public
* @param bool $scalars If the scalars data should be cleaned
* @param bool $arrays If the arrays data should be cleaned
* @param bool $arrays_ifs If the arrays_ifs data should be cleaned
* @param bool $carrays If the case arrays data should be cleaned
* @param bool $ifs If the ifs data should be cleaned
* @param bool $plugins If the plugins data should be cleaned
*/
function reset($scalars=false, $arrays=false, $arrays_ifs=false, $carrays=false, $ifs=false,$plugins=false)
{
if($scalars) $this->_scalars = array();
if($arrays) $this->_arrays = array();
if($arrays_ifs) $this->_arrays_ifs = array();
if($carrays) $this->_carrays = array();
if($ifs) $this->_ifs = array();
if($plugins) $this->_plugins = array();
}
/**
* Formats the tags & returns a two-element array, 格式化标签并且返回一个两个元素的数组
* the opening and closing tags 开始与结束标签
*
* @access public
* @param string $tag The tag name
* @param string $directive The directive name
* @return array
*/
function get_tags($tag, $directive)
{
$tags['b'] = $this->BAldelim . $directive . ':' . $tag . $this->BArdelim; //如{
$tags['e'] = $this->EAldelim . $directive . ':' . $tag . $this->EArdelim;
return $tags;
}
/**
* Formats a simple tag
*
* @access public
* @param string $tag The tag name
* @param string $directive The tag directive
* @return string The formated tag
*/
function get_tag($tag,$directive='tag')
{
return $this->ldelim . $directive . ':' . $tag . $this->rdelim;
}
/**
* Extracts a portion of a template( or a string) according to the
* opening ($tags['b']) and closing ($tags['e']) tags
*
* @param array $tags The opening and closing tags/delimeters
* @param string $contents The content from where it is going to extract
* @return string The extracted content
*/
function get_statement($tags, $contents)
{
// Locate the statement
$tag_length = strlen($tags['b']);
$fpos = $tags['b']===null? 0 : strpos($contents, $tags['b']);
$lpos = $tags['e']===null? strlen($contents) : strpos($contents, $tags['e']);
if($fpos===false||$lpos===false)
return false;
$fpos += $tag_length;
$length = $lpos - $fpos;
// Extract & return the statement
return substr($contents, $fpos, $length);
}
/**
* Parse the template with the variables 解析模板变量
*
* @access public
* @param string $contents The template
* @return string The parsed template
*/
function parse($contents)
{
/**
* Process the ifs (if any)
*/
foreach($this->_ifs as $value)
{
$contents = $this->_parse_if($value, $contents);
}
/**
* Process the scalars (if any)
*/
foreach($this->_scalars as $key => $value)
{
$contents = str_replace($this->get_tag($key), $value, $contents);
}
/**
* Process the arrays (if any)
*/
foreach($this->_arrays as $key => $array)
{
$contents = $this->_parse_loop($key, $array, $contents);
}
/**
* Process the case arrays (if any)
*/
foreach($this->_carrays as $key => $array)
{
$contents = $this->_parse_cloop($key, $array, $contents);
}
$plugins_count=count($this->_plugins);
/**
* Process the plugins (if any)
*/
for ($n=0;$n<$plugins_count;$n++)
{
if($this->_plugins[$n]['object']===null)
$obj=new $this->_plugins[$n]['function']();
else
$obj=&$this->_plugins[$n]['object'];
//
//Now we check what protocol version the plugin was designed for
//
switch ($obj->version('protocol'))
{
case "1.0":
{
//
//Now we give the object itself to the function, so it can access the current settings
//
$contents=$obj->parse($contents,$this);
}break;
}
}
/**
* Reset the data according to the settings
*/
if($this->reset) $this->reset(FALSE, TRUE, TRUE, TRUE);
return $contents;
}
/**
* Parses an if statement //解析一个if...esle...语句,示例:{if:标签}...{else:标签}...{/if:标签}
*
* @access private
* @param string $tag The tag name
* @param string $contents The current as-processed template
* @param string $replace If the function should consider as $replace without checking the real value
* @return string The parsed template
*/
function _parse_if($tag, $contents, $replace=null)
{
//
// Get the tags
//
$t = $this->get_tags($tag, 'if'); //返回一个$t数组,值分别为:$t['b']="{if:标签$tag}",$t['e']="{/if:标签$tag}",如:{if:test}{/if:test}
//
//We loop this so we can process all the ifs for this tag
//
while (($entire_statement = $this->get_statement($t, $contents))!==false)
{
// Get the else tag 获取else标签
$tags['b'] = NULL;
$tags['e'] = $this->get_tag($tag, 'else');
// See if there's an else statement 判断是否有else语句
if(($else = strpos($entire_statement, $tags['e'])))
{
// Get the if statement
$if = $this->get_statement($tags, $entire_statement);
// Get the else statement
$else = substr($entire_statement, $else + strlen($tags['e']));
}
else
{
$else = NULL;
$if = $entire_statement;
}
//
//If the function wasn't called with a value for $replace we check the _scalars array
//
if($replace===null||!is_bool($replace))
$replace=!empty($this->_scalars[$tag])?true:false;
//
//If the condition is valid then we use the 'if' (first) part, if not, then we use 'else'
//
$replace=($replace) ? $if : $else;
//
// Parse the template
//
$contents = str_replace($t['b'] . $entire_statement . $t['e'], $replace, $contents);
}
//
//Return the template
//
return $contents;
}
/**
* Parses a loop //解析一个loop语句,示例:{loop:标签}...{/loop:标签}
*
* @access private
* @param string $tag Tag name
* @param array $array The array containing the loop data
* @param string $contents The current as-processed template
* @return string The parsed template
*/
function _parse_loop($tag, $array, $contents)
{
// Get the tags & loop
$t = $this->get_tags($tag, 'loop');
while (($loop = $this->get_statement($t, $contents))!==false)
{
$parsed = NULL;
$if_key_exists=isset($this->_arrays_ifs[$tag]);
// Process the loop
foreach($array as $key => $value)
{
/**
* We create a copy of the loop so we can keep the original loop
* but work on this one
*/
$i = $loop;
if($if_key_exists&&isset($this->_arrays_ifs[$tag][$key]))
$i=$this->_parse_if($tag . '.' . $key,$i,!empty($value)?true:false);
/**
* array(1=>array('key_name'=>'value','some_key'=>'value'))
* {tag:tag_name[].key_name},{tag:tag_name[].some_key}
* {tag:tag_name[].key_name[]},{tag:tag_name[].some_key[].some_subkey}
*/
if(is_numeric($key) && is_array($value))
{
foreach($value as $key2 => $value2)
{
if($if_key_exists&&isset($this->_arrays_ifs[$tag][$key2]))
$i=$this->_parse_if($tag . '[].' . $key2,$i,!empty($value2)?true:false);
if(!is_array($value2))
{
// Replace associative array tags
$i = str_replace($this->get_tag($tag . '[].' . $key2), $value2, $i);
}
else
{
// Check to see if it's a nested loop
$i = $this->_parse_loop($tag . '[].' . $key2, $value2, $i);
}
}
}
/**
* array('tsgsgs'=>'sgsgdgg')
* {tag:tag_name.key_name}
*/
elseif(is_string($key) && !is_array($value))
{
$i = str_replace($this->get_tag($tag . '.' . $key), $value, $i);
}
/**
* array(1=>'fff')
* {tag:tag_name[]}
*/
elseif(!is_array($value))
{
$i = str_replace($this->get_tag($tag . '[]'), $value, $i);
}
// Add the parsed iteration
if(isset($i)) $parsed .= rtrim($i);
}
//
// Parse the template
//
$contents=str_replace($t['b'] . $loop . $t['e'], $parsed, $contents);
}
//
//Return the template
//
return $contents;
}
/**
* Parse a case loop 解析一个case循环语句,相当于switch一样
*
* @access private
* @param string $tag The tag name that is going to be parsed
* @param array $array Array with the loop elements
* @param string $contents The current as-processed template
* @return string The parsed template
*/
function _parse_cloop($tag, $array, $contents)
{
// Get the tags & loop
$t = $this->get_tags($tag, 'cloop'); //返回{cloop:名称}{case:名称}...{default:名称}{/cloop:名称}
while (($loop = $this->get_statement($t, $contents))!==false)
{
// Set up the cases
$array['cases'][] = 'default';
$case_content = array();
$parsed = NULL;
// Get the case strings
foreach($array['cases'] as $case)
{
$ctags[$case] = $this->get_tags($case, 'case');
$case_content[$case] = $this->get_statement($ctags[$case], $loop);
}
// Process the loop
foreach($array['array'] as $key => $value)
{
if(is_numeric($key) && is_array($value))
{
// Set up the cases
if(isset($value['case'])) $current_case = $value['case'];
else $current_case = 'default';
unset($value['case']);
$i = $case_content[$current_case];
// Loop through each value
foreach($value as $key2 => $value2) {
$i = str_replace($this->get_tag($tag . '[].' . $key2), $value2, $i);
}
}
// Add the parsed iteration
$parsed .= rtrim($i);
}
// Parse & return the final loop
$contents=str_replace($t['b'] . $loop . $t['e'], $parsed, $contents);
}
return $contents;
}
/**
* Parses the file $file_name as a template
*
* @access public
* @param string $file The template file name
* @return string The processed template
*/
function fetch($file,$filename = '')
{
// Open the file
$fp = fopen($file, 'rb');
if(!$fp) return FALSE;
// Read the file
$contents = fread($fp, filesize($file));
// Close the file
fclose($fp);
// Parse and return the contents
if (empty($filename)){
/*------------------------------------*/
//动态浏览
return $this->parse($contents);
/*------------------------------------*/
}else{
/*------------------------------------*/
//生成静态页面
$content = $this->parse($contents);
$handle = fopen ($filename,"w"); //打开文件指针,创建文件
/*
检查文件是否被创建且可写
*/
if (!is_writable ($filename)){
//die ("文件:".$filename."不可写,请检查其属性后重试!");
}
if (!fwrite ($handle,$content)){ //将信息写入文件
//die ("生成文件".$filename."失败!");
}
fclose ($handle); //关闭指针
/*------------------------------------*/
}
}
/**
* Works the same way as set() excepting that if the tag already exists //除了if标签已经存在以外,功能与set()一样
* it doesn't replaces it, it appends the new value (if it is an string)
* or it merges the content (if it is an array). //append()不能代替set(),append() 添加一个新值(如果这个值是一个字符串),或者添加一个元素(如果它是一个数组)
* Please note that this function will not make any change
* to the array_ifs data, to update that information,//请注意这个函数对array_ifs数据更新信息不会产生任何改变
* set() has to be used instead //set()函数则一定会替换旧的值
*
* @param string $tag
* @param mixed $var
* @param bool $if
*/
function append($tag, $var, $if = NULL)
{
if(is_array($var))
{
if(!isset($this->_arrays[$tag]))
$this->_arrays[$tag]= $var;
else
$this->_arrays[$tag]=array_merge($this->_arrays[$tag],$var);
if($if)
{
$result = $var ? TRUE : FALSE;
$this->_ifs[] = $tag;
$this->_scalars[$tag] = $result;
}
}
else
{
if(!isset($this->_scalars[$tag]))
$this->_scalars[$tag] = $var;
else
$this->_scalars[$tag] .= $var;
if($if) $this->_ifs[] = $tag;
}
}
/**
* Adds a plugin to be called when a template is being parsed
* The $plugin_name is the name of the class which is the plugin
*
* The $setup var may contain any type of data, because it is pased directly to the $plugin_name::setup() function of the plugin class
* The arguments passed to the $plugin_name::parse() function will be $contents and the object itself ($this), in that order, and the function will only return the parsed template.
*
* The $plugin_name::setup() function may return an array with some settings
*
* Notes:
* The plugin class must have the next functions, which are going to be called by the template engine:
* -$plugin_name::setup() This function can be used to setup either the template engine when calling the plugin or to setup the plugin itself, in the last case, the $setup param can be used to give some settings to the plugin
* -$plugin_name::parse() This function is called when the class 'executes' the plugin
* -$plugin_name::version() This function must have one argument, which specifies the version of what is being requested: 'protocol' is the current plugins protocol, for the current version is 1.0; 'plugin' is the plugin version, it can be useful to debug
*
* @access public
* @param string $plugin_name The name of the function or class to be called
* @param mixed $setup Special settings that can be given to the plugin
*/
function add_plugin($plugin_name,$setup=null)
{
$n=count($this->_plugins);
$this->_plugins[$n]['function']=$plugin_name;
$this->_plugins[$n]['setup']=$setup;
$obj=new $plugin_name();
$this->_plugins[$n]=array_merge($this->_plugins[$n],$obj->setup($setup));
if (!isset($this->_plugins[$n]['refresh_object'])||$this->_plugins[$n]['refresh_object']===false)
$this->_plugins[$n]['object']=&$obj;
else
$this->_plugins[$n]['object']=null;
}
}
?>
=================================
示例
=================================
将以上代码保存到Template_class.php文件中.看不看得懂并不重要,只要看懂以下代码学会用就可以了,以下主要的代码我都加在后面******号,其它的代码可有可无,自已写就得了,灵活运用
--------------------------------
调用类的测试页 test.php 相关代码
--------------------------------
<?php
include ("conn.php");//创建数据库链接
include ("mysql_func.php");//自定义的一个数据库处理页面
require_once("Template_class.php");//******这是上面的模板处理类页面
$tpl=new Template_class();//******创建对象
$sql = "select * from test ";
genpage($sql,15);//这是一个分页函数,具体代码在mysql_func.php里,统计总页数,并返回一个$sql语句,以便下面这行使用,15为每页显示的记录数
$result = mysql_query($sql);
while($rs =mysql_fetch_array($result))
{
$test[] = array("str"=>"$rs[str]");//******这个数组的名称很重要,也可以自定义,但要与下面set里的参数$test名称相同,最好三个参数的名称都一样,如下面的test,如果页面里不用显示数据列表的话,此数组可省略,str为数据库表里的一个字段名称
//上面这里只以显示一个字段为例,如果有多个字段则$test[] = array("str"=>"$rs[str]","字段名称"=>"值",...);
}
//******以下set()函数比较重要,主要是将模板面里的相关标签替换为相关值,$tpl->set("标签名称","要替换的值");
$tpl->set("test",$test,array("test"=>true));//将数据替换到静态模板页相关位置,注意后面的array("test"=>true)这个参数,一般是显示数据列表时用到
$tpl->set("showpage",showpage());//******将分页代码插入静态模板页的指定位置
$tpl->set("title","测试调用模板处理类");//******如果只是一个字符串的话,可以这样子
//...根据模板页面设置好的标签多少在此增加或减少$tpl->set()
die($tpl->fetch("mode.html"));//******将数据填充入静态模板页mode.html并直接显示出来,不生成静态页面
//如果需要生成静态页面的话,那么上一句这样写即可,die($tpl->fetch("模板页的路径及名称","要生成页面的路径及名称"));如die($tpl->fetch("mode.html","/1/1.html"));
?>
--------------------------------
静态模板页 mode.html 相关代码
--------------------------------
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
</head>
<body>
<table>
<tr><td>{tag:title}<!--这里就是上面那个tpl->set("title","测试调用模板处理类");要替换的位置--></td></tr>
<!--下面开始循环显示记录,下面的那个:号左边的标签test可以改变,但要对应正确-->
{if:test}
{loop:test}
<tr>
<td align="center">{tag:test[].str}</td>
<!--
如果有更多字段的话
<td align="center">{tag:test[].str2}</td>
<td align="center">{tag:test[].str3}</td>
...
-->
</tr>
{/loop:test}
{else:test}
<tr>
<td height="100" align="center">没有数据</td>
</tr>
{/if:test}
</table>
<table width="100%" border="0" cellpadding="0" cellspacing="0">
<tr>
<td>{tag:showpage}<!--这里是分页处--></td>
</tr>
</table>
</body>
</html>
ok,就说到这了,其它的就自已去研究与测试吧,呵呵
文章来源:桂林唯创网络