写一个MVC的模板解析方法

把业务逻辑处理从用户界面视图中分离出来
服务器君一共花费了1347.432 ms进行了5次数据库查询,努力地为您提供了这个页面。
试试阅读模式?希望听取您的建议

MVC是模型(Model)、视图(View)和控制(Controller)的缩写,PHP中采用MVC模式的目的是实现Web系统的职能分工,通俗的说就是把业务逻辑处理从用户界面视图中分离出来。使Web系统的开发与维护更加方便,从而有效的节省人力物力,受到了越来越多企业的青睐。

模板引擎是MVC模式建立过程的重要方法,开发者可以设计一套赋予含义的标签,通过技术解析处理有效的把数据逻辑处理从界面模板中提取出来,通过解读标签的含义把控制权提交给相应业务逻辑处理程序,从而获取到需要的数据,以模板设计的形式展现出来,使设计人员能把精力更多放在表现形式上。下面是我对模板引擎的认识与设计方法:

说的好听些叫模板引擎,实际就是解读模板数据的过程(个人观点^^)。通过我对建站方面的思考认识,网站在展现形式上无非归纳为单条和多条两种形式,那么我们可以设定两种对应标签(如data、list)来处理这两种情况,关键点在于解决两种标签的多层相互嵌套问题,基本适合实现80%界面形式。

解读模板的方法有多种,常用的包括字符串处理(解决嵌套稍麻烦)、正则表达式。在这里我选用的正则表达式,下面是我的处理方法(本文仅提供思路和参考代码,可能不能直接使用)。

模板文件解析类:

<?php
       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.')[\S\s]*?|(?R))*)'.$this->eTag.'\\1\s*'.$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*([\S\s]+)$';
                                       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() {}
       }
?>

标签解析类:(目前暂时提供data、list两种标签的解析,说明思路)

<?php
       class Tags {
             static private $attrs=null;
             static public  $file, $vars, $rule, $prefix='TAG_';
             static public function TAG_Syntax($html, $that) {                
                 $rule = $that->bTag.'if\s+([^'.$that->eFlag.']+)\s*'.$that->eFlag;
                 $html = preg_replace('/'.$rule.'/ism', '<?php if (\\1) { ?>', $html);
                 $rule = $that->bTag.'elseif\s+([^'.$that->eFlag.']+)\s*'.$that->eFlag;
                 $html = preg_replace('/'.$rule.'/ism', '<?php } elseif (\\1) { ?>', $html);
                 $rule = $that->bTag.'else\s*'.$that->eFlag;
                 $html = preg_replace('/'.$rule.'/ism', '<?php } else { ?>', $html);
                 $rule = $that->bTag.'loop\s+(\S+)\s+(\S+)\s*'.$that->eFlag;
                 $html = preg_replace('/'.$rule.'/ism', '<?php foreach (\\1 as \\2) { ?>', $html);
                 $rule = $that->bTag.'loop\s+(\S+)\s+(\S+)\s+(\S+)\s*'.$that->eFlag;
                 $html = preg_replace('/'.$rule.'/ism', '<?php foreach (\\1 as \\2 => \\3) { ?>', $html);
                 $rule = $that->eTag.'(if|loop)\s*'.$that->eFlag;
                 $html = preg_replace('/'.$rule.'/ism', '<?php } ?>', $html);
                 $rule = $that->bTag.'php\s*'.$that->eFlag.'((?:(?!'.
                         $that->bTag.')[\S\s]*?|(?R))*)'.$that->eTag.'php\s*'.$that->eFlag;
                 $html = preg_replace('/'.$rule.'/ism', '<?php \\1 ?>', $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.')[\S\s]*?|(?R))*)'.$tpl_ins->eTag.'\\1\s*'.$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.nowamagic.net/librarys/veda/detail/1127,欢迎访问原出处。

不打个分吗?

转载随意,但请带上本文地址:

http://www.nowamagic.net/librarys/veda/detail/1127

如果你认为这篇文章值得更多人阅读,欢迎使用下面的分享功能。
小提示:您可以按快捷键 Ctrl + D,或点此 加入收藏

大家都在看

阅读一百本计算机著作吧,少年

很多人觉得自己技术进步很慢,学习效率低,我觉得一个重要原因是看的书少了。多少是多呢?起码得看3、4、5、6米吧。给个具体的数量,那就100本书吧。很多人知识结构不好而且不系统,因为在特定领域有一个足够量的知识量+足够良好的知识结构,系统化以后就足以应对大量未曾遇到过的问题。

奉劝自学者:构建特定领域的知识结构体系的路径中再也没有比学习该专业的专业课程更好的了。如果我的知识结构体系足以囊括面试官的大部分甚至吞并他的知识结构体系的话,读到他言语中的一个词我们就已经知道他要表达什么,我们可以让他坐“上位”毕竟他是面试官,但是在知识结构体系以及心理上我们就居高临下。

所以,阅读一百本计算机著作吧,少年!

《致加西亚的信》 阿尔伯特·哈伯德(Hubbard.E.) (作者), 赵立光 (译者), 艾柯 (译者)

《致加西亚的信(经典盒装版)》内容简介:美西战争爆发以后,美国必须立即与古巴起义军首领加西亚取得联系,并获得他的合作。但当时,加西亚身在古巴的深山里——没有人知道他的确切地点,所以没法与他取得联系。这时,有人向总统推荐一个名叫罗文的人,说他有办法找到加西亚,而且也只有他才能找得到。他们找来罗文,交给他一封写给加西亚的信。三周后,罗文徒步走过一个危机四伏的国家,最终把那封信交给了加西亚。 此后,罗文的事迹被传为佳话,“送信”成为了敬业、忠诚、勤奋的象征,罗文便成了每个领导都想找到的人和每个员工都应该学习和效仿的榜样。

更多计算机宝库...