It makes the development and maintenance of Web systems more convenient, thereby effectively saving manpower and material resources, and is favored by more and more enterprises.
The template engine is an important method in the MVC pattern establishment process. Developers can design a set of tags that give meaning, and effectively extract the data logic processing from the interface template through technical analysis and interpretation of the meaning of the tags. Submit the control rights to the corresponding business logic processing program to obtain the required data and display it in the form of template design, so that designers can focus more on the form of expression. The following is my understanding and design method of template engines:
To put it nicely, it is called a template engine, but it is actually the process of interpreting template data (personal opinion^^). Through my thinking and understanding of website building, the presentation form of the website can be summarized into two forms: single item and multiple items. Then we can set two corresponding tags (such as data, list) to handle these two situations. The key point is It solves the problem of multi-layer nesting of two tags and is basically suitable for realizing 80% of interface forms.
There are many ways to interpret templates, commonly used ones include string processing (resolving nesting is a little troublesome) and regular expressions. The regular expression I chose here, and the following is my processing method (this article only provides ideas and reference code, which may not be used directly).
Template file parsing class:
Copy code The code is as follows:
/*
* class: 模板解析类
* author: 51JS.COM-ZMM
* date: 2011.3.1
* email: 304924248@qq.com
* blog: http://www.cnblogs.com/cnzmm/
*/
class Template {
public $html, $vars, $bTag, $eTag;
public $bFlag='{', $eFlag='}', $pfix='zmm:';
private $folder, $file;
function __construct($vars=array()) {
!empty($vars) && $this->vars = $vars;
!empty($GLOBALS['cfg_tag_prefix']) &&
$this->pfix = $GLOBALS['cfg_tag_prefix'].':';
$this->bTag = $this->bFlag.$this->pfix;
$this->eTag = $this->bFlag.'/'.$this->pfix;
empty(Tags::$vars) && Tags::$vars = &$this->vars;
}
public function LoadTpl($tpl) {
$this->file = $this->GetTplPath($tpl);
Tags::$file = &$this->file;
if (is_file($this->file)) {
if ($this->GetTplHtml()) {
$this->SetTplTags();
} else {
exit('模板文件加载失败!');
}
} else {
exit('模板文件['.$this->file.']不存在!');
}
}
private function GetTplPath($tpl) {
$this->folder = WEBSITE_DIRROOT.
$GLOBALS['cfg_tpl_root'];
return $this->folder.'/'.$tpl;
}
private function GetTplHtml() {
$html = self::FmtTplHtml(file_get_contents($this->file));
if (!empty($html)) {
$callFunc = Tags::$prefix.'Syntax';
$this->html = Tags::$callFunc($html, new Template());
} else {
exit('模板文件内容为空!');
} return true;
}
static public function FmtTplHtml($html) {
return preg_replace('/(r)|(n)|(t)|(s{2,})/is', '', $html);
}
public function Register($vars=array()) {
if (is_array($vars)) {
$this->vars = $vars;
Tags::$vars = &$this->vars;
}
}
public function Display($bool=false, $name="", $time=0) {
if (!empty($this->html)) {
if ($bool && !empty($name)) {
if (!is_int($time)) $time = 600;
$cache = new Cache($time);
$cache->Set($name, $this->html);
}
echo $this->html; flush();
} else {
exit('模板文件内容为空!');
}
}
public function SetAssign($souc, $info) {
if (!empty($this->html)) {
$this->html = str_ireplace($souc, self::FmtTplHtml($info), $this->html);
} else {
exit('模板文件内容为空!');
}
}
private function SetTplTags() {
$this->SetPanelTags(); $this->SetTrunkTags(); $this->RegHatchVars();
}
private function SetPanelTags() {
$rule = $this->bTag.'([^'.$this->eFlag.']+)/'.$this->eFlag;
preg_match_all('/'.$rule.'/ism', $this->html, $out_matches);
$this->TransTag($out_matches, 'panel'); unset($out_matches);
}
private function SetTrunkTags() {
$rule = $this->bTag.'(w+)s*([^'.$this->eFlag.']*?)'.$this->eFlag.
'((?:(?!'.$this->bTag.')[Ss]*?|(?R))*)'.$this->eTag.'\1s*'.$this->eFlag;
preg_match_all('/'.$rule.'/ism', $this->html, $out_matches);
$this->TransTag($out_matches, 'trunk'); unset($out_matches);
}
private function TransTag($result, $type) {
if (!empty($result[0])) {
switch ($type) {
case 'panel' : {
for ($i = 0; $i < count($result[0]); $i ++) {
$strTag = explode(' ', $result[1][$i], 2);
if (strpos($strTag[0], '.')) {
$itemArg = explode('.', $result[1][$i], 2);
$callFunc = Tags::$prefix.ucfirst($itemArg[0]);
if (method_exists('Tags', $callFunc)) {
$html = Tags::$callFunc(chop($itemArg[1]));
if ($html !== false) {
$this->html = str_ireplace($result[0][$i], $html, $this->html);
}
}
} else {
$rule = '^([^s]+)s*([Ss]+)$';
preg_match_all('/'.$rule.'/is', trim($result[1][$i]), $tmp_matches);
$callFunc = Tags::$prefix.ucfirst($tmp_matches[1][0]);
if (method_exists('Tags', $callFunc)) {
$html = Tags::$callFunc($tmp_matches[2][0]);
if ($html !== false) {
$this->html = str_ireplace($result[0][$i], $html, $this->html);
}
} unset($tmp_matches);
}
} break;
}
case 'trunk' : {
for ($i = 0; $i < count($result[0]); $i ++) {
$callFunc = Tags::$prefix.ucfirst($result[1][$i]);
if (method_exists('Tags', $callFunc)) {
$html = Tags::$callFunc($result[2][$i], $result[3][$i]);
$this->html = str_ireplace($result[0][$i], $html, $this->html);
}
} break;
}
default: break;
}
} else {
return false;
}
}
private function RegHatchVars() {
$this->SetPanelTags();
}
function __destruct() {}
}
?>
Tag parsing class: (Currently, we provide parsing of data and list tags to explain the ideas)
Copy code The code is as follows:
/*
* class: 标签解析类
* author: 51JS.COM-ZMM
* date: 2011.3.2
* email: 304924248@qq.com
* blog: http://www.cnblogs.com/cnzmm/
*/
class Tags {
static private $attrs=null;
static public $file, $vars, $rule, $prefix='TAG_';
static public function TAG_Syntax($html, $that) {
$rule = $that->bTag.'ifs+([^'.$that->eFlag.']+)s*'.$that->eFlag;
$html = preg_replace('/'.$rule.'/ism', '', $html);
$rule = $that->bTag.'elseifs+([^'.$that->eFlag.']+)s*'.$that->eFlag;
$html = preg_replace('/'.$rule.'/ism', '', $html);
$rule = $that->bTag.'elses*'.$that->eFlag;
$html = preg_replace('/'.$rule.'/ism', '', $html);
$rule = $that->bTag.'loops+(S+)s+(S+)s*'.$that->eFlag;
$html = preg_replace('/'.$rule.'/ism', '', $html);
$rule = $that->bTag.'loops+(S+)s+(S+)s+(S+)s*'.$that->eFlag;
$html = preg_replace('/'.$rule.'/ism', ' \3) { ?>', $html);
$rule = $that->eTag.'(if|loop)s*'.$that->eFlag;
$html = preg_replace('/'.$rule.'/ism', '', $html);
$rule = $that->bTag.'phps*'.$that->eFlag.'((?:(?!'.
$that->bTag.')[Ss]*?|(?R))*)'.$that->eTag.'phps*'.$that->eFlag;
$html = preg_replace('/'.$rule.'/ism', '', $html);
return self::TAG_Execute($html);
}
static public function TAG_List($attr, $html) {
if (!empty($html)) {
if (self::TAG_HaveTag($html)) {
return self::TAG_DealTag($attr, $html, true);
} else {
return self::TAG_GetData($attr, $html, true);
}
} else {
exit('标签{list}的内容为空!');
}
}
static public function TAG_Data($attr, $html) {
if (!empty($html)) {
if (self::TAG_HaveTag($html)) {
return self::TAG_DealTag($attr, $html, false);
} else {
return self::TAG_GetData($attr, $html, false);
}
} else {
exit('标签{data}的内容为空!');
}
}
static public function TAG_Execute($html) {
ob_clean(); ob_start();
if (!empty(self::$vars)) {
is_array(self::$vars) &&
extract(self::$vars, EXTR_OVERWRITE);
}
$file_inc = WEBSITE_DIRINC.'/buffer/'.
md5(uniqid(rand(), true)).'.php';
if ($fp = fopen($file_inc, 'xb')) {
fwrite($fp, $html);
if (fclose($fp)) {
include($file_inc);
$html = ob_get_contents();
} unset($fp);
} else {
exit('模板解析文件生成失败!');
} ob_end_clean(); @unlink($file_inc);
return $html;
}
static private function TAG_HaveTag($html) {
$bool_has = false;
$tpl_ins = new Template();
self::$rule = $tpl_ins->bTag.'([^'.$tpl_ins->eFlag.']+)/'.$tpl_ins->eFlag;
$bool_has = $bool_has || preg_match('/'.self::$rule.'/ism', $html);
self::$rule = $tpl_ins->bTag.'(w+)s*([^'.$tpl_ins->eFlag.']*?)'.$tpl_ins->eFlag.
'((?:(?!'.$tpl_ins->bTag.')[Ss]*?|(?R))*)'.$tpl_ins->eTag.'\1s*'.$tpl_ins->eFlag;
$bool_has = $bool_has || preg_match('/'.self::$rule.'/ism', $html);
unset($tpl_ins);
return $bool_has;
}
static private function TAG_DealTag($attr, $html, $list) {
preg_match_all('/'.self::$rule.'/ism', $html, $out_matches);
if (!empty($out_matches[0])) {
$child_node = array();
for ($i = 0; $i < count($out_matches[0]); $i ++) {
$child_node[] = $out_matches[3][$i];
$html = str_ireplace($out_matches[3][$i], '{-->>child_node_'.$i.'<<--}', $html);
}
$html = self::TAG_GetData($attr, $html, $list);
for ($i = 0; $i < count($out_matches[0]); $i ++) {
$html = str_ireplace('{-->>child_node_'.$i.'<<--}', $child_node[$i], $html);
}
preg_match_all('/'.self::$rule.'/ism', $html, $tmp_matches);
if (!empty($tmp_matches[0])) {
for ($i = 0; $i < count($tmp_matches[0]); $i ++) {
$callFunc = self::$prefix.ucfirst($tmp_matches[1][$i]);
if (method_exists('Tags', $callFunc)) {
$temp = self::$callFunc($tmp_matches[2][$i], $tmp_matches[3][$i]);
$html = str_ireplace($tmp_matches[0][$i], $temp, $html);
}
}
}
unset($tmp_matches);
}
unset($out_matches); return $html;
}
static private function TAG_GetData($attr, $html, $list=false) {
if (!empty($attr)) {
$attr_ins = new Attbt($attr);
$attr_arr = $attr_ins->attrs;
if (is_array($attr_arr)) {
extract($attr_arr, EXTR_OVERWRITE);
$source = table_name($source, $column);
$rule = '[field:s*(w+)s*([^]]*?)s*/?]';
preg_match_all('/'.$rule.'/is', $html, $out_matches);
$data_str = '';
$data_ins = new DataSql();
$attr_where = $attr_order = '';
if (!empty($where)) {
$where = str_replace(',', ' and ', $where);
$attr_where = ' where '. $where;
}
if (!empty($order)) {
$attr_order = ' order by '.$order;
} else {
$fed_name = '';
$fed_ins = $data_ins->GetFedNeedle($source);
$fed_cnt = $data_ins->GetFedCount($fed_ins);
for ($i = 0; $i < $fed_cnt; $i ++) {
$fed_flag = $data_ins->GetFedFlag($fed_ins, $i);
if (preg_match('/auto_increment/ism', $fed_flag)) {
$fed_name = $data_ins->GetFedName($fed_ins, $i);
break;
}
}
if (!empty($fed_name))
$attr_order = ' order by '.$fed_name.' desc';
}
if ($list == true) {
if (empty($source) && empty($sql)) {
exit('标签{list}必须指定source属性!');
}
$attr_rows = $attr_page = '';
if ($rows > 0) {
$attr_rows = ' limit 0,'.$rows;
}
if (!empty($sql)) {
$data_sql = $sql;
} else {
$data_sql = 'select * from `'.$source.'`'.
$attr_where.$attr_order.$attr_rows;
}
if ($pages=='true' && !empty($size)) {
$data_num = $data_ins->GetRecNum($data_sql);
$page_cnt = ceil($data_num / $size);
global $page;
if (!isset($page) || $page < 1) $page = 1;
if ($page > $page_cnt) $page = $page_cnt;
$data_sql = 'select * from `'.$source.'`'.$attr_where.
$attr_order.' limit '.($page-1) * $size.','.$size;
$GLOBALS['cfg_page_curr'] = $page;
$GLOBALS['cfg_page_prev'] = $page - 1;
$GLOBALS['cfg_page_next'] = $page + 1;
$GLOBALS['cfg_page_nums'] = $page_cnt;
if (function_exists('list_pagelink')) {
$GLOBALS['cfg_page_list'] = list_pagelink($page, $page_cnt, 2);
}
}
$data_idx = 0;
$data_ret = $data_ins->SqlCmdExec($data_sql);
while ($row = $data_ins->GetRecArr($data_ret)) {
if ($skip > 0 && !empty($flag)) {
$data_idx != 0 &&
$data_idx % $skip == 0 &&
$data_str .= $flag;
}
$data_tmp = $html;
$data_tmp = str_ireplace('@idx', $data_idx, $data_tmp);
for ($i = 0; $i < count($out_matches[0]); $i ++) {
$data_tmp = str_ireplace($out_matches[0][$i],
$row[$out_matches[1][$i]], $data_tmp);
}
$data_str .= $data_tmp; $data_idx ++;
}
} else {
if (empty($source)) {
exit('标签{data}必须指定source属性!');
}
$data_sql = 'select * from `'.$source.
'`'.$attr_where.$attr_order;
$row = $data_ins->GetOneRec($data_sql);
if (is_array($row)) {
$data_tmp = $html;
for ($i = 0; $i < count($out_matches[0]); $i ++) {
$data_val = $row[$out_matches[1][$i]];
if (empty($out_matches[2][$i])) {
$data_tmp = str_ireplace($out_matches[0][$i], $data_val, $data_tmp);
} else {
$attr_str = $out_matches[2][$i];
$attr_ins = new Attbt($attr_str);
$func_txt = $attr_ins->attrs['function'];
if (!empty($func_txt)) {
$func_tmp = explode('(', $func_txt);
if (function_exists($func_tmp[0])) {
eval('$func_ret ='.str_ireplace('@me',
'''.$data_val.''', $func_txt));
$data_tmp = str_ireplace($out_matches[0][$i], $func_ret, $data_tmp);
} else {
exit('调用了不存在的函数!');
}
} else {
exit('标签设置属性无效!');
}
}
}
$data_str .= $data_tmp;
}
}
unset($data_ins);
return $data_str;
} else {
exit('标签设置属性无效!');
}
} else {
exit('没有设置标签属性!');
}
}
static public function __callStatic($name, $args) {
exit('标签{'.$name.'}不存在!');
}
}
?>
http://www.bkjia.com/PHPjc/323031.htmlwww.bkjia.comtruehttp://www.bkjia.com/PHPjc/323031.htmlTechArticle使Web系统的开发与维护更加方便,从而有效的节省人力物力,受到了越来越多企业的青眯。 模板引擎是MVC模式建立过程的重要方法,开发者...