首頁 php教程 php手册 写一个MVC的模板解析方法

写一个MVC的模板解析方法

Jun 13, 2016 am 09:39 AM
mvc

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.'}不存在!');
             }
       }
?>
登入後複製
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

PHP MVC 架構:建立面向未來的 Web 應用程式 PHP MVC 架構:建立面向未來的 Web 應用程式 Mar 03, 2024 am 09:01 AM

引言在當今快速發展的數位世界中,建立健壯、靈活且可維護的WEB應用程式至關重要。 PHPmvc架構提供了實現這一目標的理想解決方案。 MVC(模型-視圖-控制器)是一種廣泛使用的設計模式,可將應用程式的各個方面分離為獨立的元件。 MVC架構的基礎MVC架構的核心原理是分離關注點:模型:封裝應用程式的資料和業務邏輯。視圖:負責呈現資料並處理使用者互動。控制器:協調模型和視圖之間的交互,管理使用者請求和業務邏輯。 PHPMVC架構phpMVC架構遵循傳統MVC模式,但也引進了語言特定的功能。以下是PHPMVC

PHP MVC 架構的進階指南:解鎖進階功能 PHP MVC 架構的進階指南:解鎖進階功能 Mar 03, 2024 am 09:23 AM

mvc架構(模型-視圖-控制器)是PHP開發中最受歡迎的模式之一,因為它為組織程式碼和簡化WEB應用程式的開發提供了清晰的結構。雖然基本的MVC原理對於大多數Web應用程式來說已經足夠,但對於需要處理複雜資料或實現高級功能的應用程序,它存在一些限制。分離模型層分離模型層是高階MVC架構常見的技術。它涉及將模型類分解為較小的子類,每個子類專注於特定功能。例如,對於一個電子商務應用程序,您可以將主模型類別分解為訂單模型、產品模型和客戶模型。這種分離有助於提高程式碼的可維護性和可重複使用性。使用依賴注入依賴

揭開SpringMVC框架的成功:它為何廣受歡迎 揭開SpringMVC框架的成功:它為何廣受歡迎 Jan 24, 2024 am 08:39 AM

SpringMVC框架解密:為什麼它如此受歡迎,需要具體程式碼範例引言:在當今的軟體開發領域中,SpringMVC框架已經成為開發者非常喜愛的一種選擇。它是基於MVC架構模式的Web框架,提供了靈活、輕量、高效的開發方式。本文將深入探討SpringMVC框架的魅力所在,並透過具體的程式碼範例來展示其強大之處。一、SpringMVC框架的優勢靈活的配置方式Spr

如何使用PHP實作MVC模式 如何使用PHP實作MVC模式 Jun 07, 2023 pm 03:40 PM

MVC(Model-View-Controller)模式是一種常用的軟體設計模式,可以幫助開發人員更好地組織和管理程式碼。 MVC模式將應用程式分為三個部分:模型(Model)、視圖(View)和控制器(Controller),每個部分都有自己的角色和職責。在本文中,我們將討論如何使用PHP實作MVC模式。模型(Model)模型代表應用程式的資料和資料處理。通常,

如何在PHP8框架中實現可擴充的MVC架構 如何在PHP8框架中實現可擴充的MVC架構 Sep 11, 2023 pm 01:27 PM

如何在PHP8框架中實現可擴展的MVC架構引言:隨著互聯網的快速發展,越來越多的網站和應用程式採用了MVC(Model-View-Controller)架構模式。 MVC架構的主要目標是將應用程式的不同部分分開,以便提高程式碼的可維護性和可擴展性。在本文中,我們將介紹如何在PHP8框架中實現可擴充的MVC架構。一、了解MVC架構模式MVC架構模式是一種軟體設

PHP中如何使用MVC架構設計項目 PHP中如何使用MVC架構設計項目 Jun 27, 2023 pm 12:18 PM

在Web開發中,MVC(Model-View-Controller)是一種常用的架構模式,用於處理和管理應用程式的資料、使用者介面和控制邏輯。 PHP作為流行的Web開發語言,也可以藉助MVC架構設計和建構Web應用程式。本文將介紹如何在PHP中使用MVC架構設計項目,並說明其優點和注意事項。什麼是MVCMVC是一種軟體架構模式,通常用於Web應用程式中。 MV

PHP8框架開發MVC:初學者需要知道的重要概念與技巧 PHP8框架開發MVC:初學者需要知道的重要概念與技巧 Sep 11, 2023 am 09:43 AM

PHP8框架開發MVC:初學者需要知道的重要概念和技巧引言:隨著網路的快速發展,Web開發在當今的軟體開發產業中扮演著重要的角色。 PHP被廣泛用於Web開發,並且有許多成熟的框架可以幫助開發人員更有效率地建立應用程式。其中,MVC(Model-View-Controller)架構是最常見且廣泛使用的模式之一。本文將介紹初學者在使用PHP8框架開發MVC應用程

揭秘 PHP MVC 架構的秘密:讓你的網站飛起來 揭秘 PHP MVC 架構的秘密:讓你的網站飛起來 Mar 03, 2024 am 09:25 AM

模型-視圖-控制器(mvc)架構是一種強大的設計模式,用於建立可維護且可擴展的WEB應用程式。 PHPMVC架構將應用程式邏輯分解為三個不同的元件:模型:表示應用程式中的資料和業務邏輯。視圖:負責呈現資料給使用者。控制器:充當模型和視圖之間的橋樑,處理使用者請求並協調其他元件。 MVC架構的優點:程式碼分離:MVC將應用程式邏輯與表示層分離,提高了可維護性和可擴充性。可重複使用性:視圖和模型元件可以跨不同的應用程式重複使用,減少重複程式碼。效能優化:MVC架構允許快取視圖和模型結果,從而提高網站速度。測試友善:分離

See all articles