<?php
//呵呵,我(wǒ)(wǒ)的英文不是很好,下(xià)面很多注釋不一(yī)定正确,懂英文的就自已看英文注釋吧,也許更容易看懂
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 = '{';//開(kāi)始标簽始端
/**
* The end of the opening tag for blocks
*
* @var string
* @access public
*/
var $BArdelim = '}';//開(kāi)始标簽末端
/**
* 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 設置一(yī)個标簽和一(yī)個值,$var變量可以是一(yī)個字符串或者一(yī)個數組
* 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, 格式化标簽并且返回一(yī)個兩個元素的數組
* the opening and closing tags 開(kāi)始與結束标簽
*
* @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 //解析一(yī)個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'); //返回一(yī)個$t數組,值分(fēn)别爲:$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 //解析一(yī)個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 解析一(yī)個case循環語句,相當于switch一(yī)樣
*
* @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{
/*------------------------------------*/
//生(shēng)成靜态頁面
$content = $this->parse($contents);
$handle = fopen ($filename,"w"); //打開(kāi)文件指針,創建文件
/*
檢查文件是否被創建且可寫
*/
if (!is_writable ($filename)){
//die ("文件:".$filename."不可寫,請檢查其屬性後重試!");
}
if (!fwrite ($handle,$content)){ //将信息寫入文件
//die ("生(shēng)成文件".$filename."失敗!");
}
fclose ($handle); //關閉指針
/*------------------------------------*/
}
}
/**
* Works the same way as set() excepting that if the tag already exists //除了if标簽已經存在以外(wài),功能與set()一(yī)樣
* 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() 添加一(yī)個新值(如果這個值是一(yī)個字符串),或者添加一(yī)個元素(如果它是一(yī)個數組)
* Please note that this function will not make any change
* to the array_ifs data, to update that information,//請注意這個函數對array_ifs數據更新信息不會産生(shēng)任何改變
* set() has to be used instead //set()函數則一(yī)定會替換舊(jiù)的值
*
* @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文件中(zhōng).看不看得懂并不重要,隻要看懂以下(xià)代碼學會用就可以了,以下(xià)主要的代碼我(wǒ)(wǒ)都加在後面******号,其它的代碼可有可無,自已寫就得了,靈活運用
--------------------------------
調用類的測試頁 test.php 相關代碼
--------------------------------
<?php
include ("conn.php");//創建數據庫鏈接
include ("mysql_func.php");//自定義的一(yī)個數據庫處理頁面
require_once("Template_class.php");//******這是上面的模闆處理類頁面
$tpl=new Template_class();//******創建對象
$sql = "select * from test ";
genpage($sql,15);//這是一(yī)個分(fēn)頁函數,具體(tǐ)代碼在mysql_func.php裏,統計總頁數,并返回一(yī)個$sql語句,以便下(xià)面這行使用,15爲每頁顯示的記錄數
$result = mysql_query($sql);
while($rs =mysql_fetch_array($result))
{
$test[] = array("str"=>"$rs[str]");//******這個數組的名稱很重要,也可以自定義,但要與下(xià)面set裏的參數$test名稱相同,最好三個參數的名稱都一(yī)樣,如下(xià)面的test,如果頁面裏不用顯示數據列表的話(huà),此數組可省略,str爲數據庫表裏的一(yī)個字段名稱
//上面這裏隻以顯示一(yī)個字段爲例,如果有多個字段則$test[] = array("str"=>"$rs[str]","字段名稱"=>"值",...);
}
//******以下(xià)set()函數比較重要,主要是将模闆面裏的相關标簽替換爲相關值,$tpl->set("标簽名稱","要替換的值");
$tpl->set("test",$test,array("test"=>true));//将數據替換到靜态模闆頁相關位置,注意後面的array("test"=>true)這個參數,一(yī)般是顯示數據列表時用到
$tpl->set("showpage",showpage());//******将分(fēn)頁代碼插入靜态模闆頁的指定位置
$tpl->set("title","測試調用模闆處理類");//******如果隻是一(yī)個字符串的話(huà),可以這樣子
//...根據模闆頁面設置好的标簽多少在此增加或減少$tpl->set()
die($tpl->fetch("mode.html"));//******将數據填充入靜态模闆頁mode.html并直接顯示出來,不生(shēng)成靜态頁面
//如果需要生(shēng)成靜态頁面的話(huà),那麽上一(yī)句這樣寫即可,die($tpl->fetch("模闆頁的路徑及名稱","要生(shēng)成頁面的路徑及名稱"));如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>
<!--下(xià)面開(kāi)始循環顯示記錄,下(xià)面的那個:号左邊的标簽test可以改變,但要對應正确-->
{if:test}
{loop:test}
<tr>
<td align="center">{tag:test[].str}</td>
<!--
如果有更多字段的話(huà)
<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}<!--這裏是分(fēn)頁處--></td>
</tr>
</table>
</body>
</html>
ok,就說到這了,其它的就自已去(qù)研究與測試吧,呵呵
//呵呵,我(wǒ)(wǒ)的英文不是很好,下(xià)面很多注釋不一(yī)定正确,懂英文的就自已看英文注釋吧,也許更容易看懂
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 = '{';//開(kāi)始标簽始端
/**
* The end of the opening tag for blocks
*
* @var string
* @access public
*/
var $BArdelim = '}';//開(kāi)始标簽末端
/**
* 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 設置一(yī)個标簽和一(yī)個值,$var變量可以是一(yī)個字符串或者一(yī)個數組
* 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, 格式化标簽并且返回一(yī)個兩個元素的數組
* the opening and closing tags 開(kāi)始與結束标簽
*
* @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 //解析一(yī)個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'); //返回一(yī)個$t數組,值分(fēn)别爲:$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 //解析一(yī)個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 解析一(yī)個case循環語句,相當于switch一(yī)樣
*
* @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{
/*------------------------------------*/
//生(shēng)成靜态頁面
$content = $this->parse($contents);
$handle = fopen ($filename,"w"); //打開(kāi)文件指針,創建文件
/*
檢查文件是否被創建且可寫
*/
if (!is_writable ($filename)){
//die ("文件:".$filename."不可寫,請檢查其屬性後重試!");
}
if (!fwrite ($handle,$content)){ //将信息寫入文件
//die ("生(shēng)成文件".$filename."失敗!");
}
fclose ($handle); //關閉指針
/*------------------------------------*/
}
}
/**
* Works the same way as set() excepting that if the tag already exists //除了if标簽已經存在以外(wài),功能與set()一(yī)樣
* 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() 添加一(yī)個新值(如果這個值是一(yī)個字符串),或者添加一(yī)個元素(如果它是一(yī)個數組)
* Please note that this function will not make any change
* to the array_ifs data, to update that information,//請注意這個函數對array_ifs數據更新信息不會産生(shēng)任何改變
* set() has to be used instead //set()函數則一(yī)定會替換舊(jiù)的值
*
* @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文件中(zhōng).看不看得懂并不重要,隻要看懂以下(xià)代碼學會用就可以了,以下(xià)主要的代碼我(wǒ)(wǒ)都加在後面******号,其它的代碼可有可無,自已寫就得了,靈活運用
--------------------------------
調用類的測試頁 test.php 相關代碼
--------------------------------
<?php
include ("conn.php");//創建數據庫鏈接
include ("mysql_func.php");//自定義的一(yī)個數據庫處理頁面
require_once("Template_class.php");//******這是上面的模闆處理類頁面
$tpl=new Template_class();//******創建對象
$sql = "select * from test ";
genpage($sql,15);//這是一(yī)個分(fēn)頁函數,具體(tǐ)代碼在mysql_func.php裏,統計總頁數,并返回一(yī)個$sql語句,以便下(xià)面這行使用,15爲每頁顯示的記錄數
$result = mysql_query($sql);
while($rs =mysql_fetch_array($result))
{
$test[] = array("str"=>"$rs[str]");//******這個數組的名稱很重要,也可以自定義,但要與下(xià)面set裏的參數$test名稱相同,最好三個參數的名稱都一(yī)樣,如下(xià)面的test,如果頁面裏不用顯示數據列表的話(huà),此數組可省略,str爲數據庫表裏的一(yī)個字段名稱
//上面這裏隻以顯示一(yī)個字段爲例,如果有多個字段則$test[] = array("str"=>"$rs[str]","字段名稱"=>"值",...);
}
//******以下(xià)set()函數比較重要,主要是将模闆面裏的相關标簽替換爲相關值,$tpl->set("标簽名稱","要替換的值");
$tpl->set("test",$test,array("test"=>true));//将數據替換到靜态模闆頁相關位置,注意後面的array("test"=>true)這個參數,一(yī)般是顯示數據列表時用到
$tpl->set("showpage",showpage());//******将分(fēn)頁代碼插入靜态模闆頁的指定位置
$tpl->set("title","測試調用模闆處理類");//******如果隻是一(yī)個字符串的話(huà),可以這樣子
//...根據模闆頁面設置好的标簽多少在此增加或減少$tpl->set()
die($tpl->fetch("mode.html"));//******将數據填充入靜态模闆頁mode.html并直接顯示出來,不生(shēng)成靜态頁面
//如果需要生(shēng)成靜态頁面的話(huà),那麽上一(yī)句這樣寫即可,die($tpl->fetch("模闆頁的路徑及名稱","要生(shēng)成頁面的路徑及名稱"));如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>
<!--下(xià)面開(kāi)始循環顯示記錄,下(xià)面的那個:号左邊的标簽test可以改變,但要對應正确-->
{if:test}
{loop:test}
<tr>
<td align="center">{tag:test[].str}</td>
<!--
如果有更多字段的話(huà)
<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}<!--這裏是分(fēn)頁處--></td>
</tr>
</table>
</body>
</html>
ok,就說到這了,其它的就自已去(qù)研究與測試吧,呵呵
文章來源:桂林唯創網絡