Home 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() {}
       }
?>
Copy after login

标签解析类:(目前暂时提供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.'}不存在!');
             }
       }
?>
Copy after login
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

PHP MVC Architecture: Building Web Applications for the Future PHP MVC Architecture: Building Web Applications for the Future Mar 03, 2024 am 09:01 AM

Introduction In today's rapidly evolving digital world, it is crucial to build robust, flexible and maintainable WEB applications. The PHPmvc architecture provides an ideal solution to achieve this goal. MVC (Model-View-Controller) is a widely used design pattern that separates various aspects of an application into independent components. The foundation of MVC architecture The core principle of MVC architecture is separation of concerns: Model: encapsulates the data and business logic of the application. View: Responsible for presenting data and handling user interaction. Controller: Coordinates the interaction between models and views, manages user requests and business logic. PHPMVC Architecture The phpMVC architecture follows the traditional MVC pattern, but also introduces language-specific features. The following is PHPMVC

An advanced guide to PHP MVC architecture: unlocking advanced features An advanced guide to PHP MVC architecture: unlocking advanced features Mar 03, 2024 am 09:23 AM

The MVC architecture (Model-View-Controller) is one of the most popular patterns in PHP development because it provides a clear structure for organizing code and simplifying the development of WEB applications. While basic MVC principles are sufficient for most web applications, it has some limitations for applications that need to handle complex data or implement advanced functionality. Separating the model layer Separating the model layer is a common technique in advanced MVC architecture. It involves breaking down a model class into smaller subclasses, each focusing on a specific functionality. For example, for an e-commerce application, you might break down the main model class into an order model, a product model, and a customer model. This separation helps improve code maintainability and reusability. Use dependency injection

Uncovering the success of the SpringMVC framework: why it is so popular Uncovering the success of the SpringMVC framework: why it is so popular Jan 24, 2024 am 08:39 AM

SpringMVC framework decrypted: Why is it so popular, specific code examples are needed Introduction: In today's software development field, the SpringMVC framework has become a very popular choice among developers. It is a Web framework based on the MVC architecture pattern, providing a flexible, lightweight, and efficient development method. This article will delve into the charm of the SpringMVC framework and demonstrate its power through specific code examples. 1. Advantages of SpringMVC framework Flexible configuration method Spr

How to implement the MVC pattern using PHP How to implement the MVC pattern using PHP Jun 07, 2023 pm 03:40 PM

The MVC (Model-View-Controller) pattern is a commonly used software design pattern that can help developers better organize and manage code. The MVC pattern divides the application into three parts: Model, View and Controller, each part has its own role and responsibilities. In this article, we will discuss how to implement the MVC pattern using PHP. Model A model represents an application's data and data processing. usually,

How to implement scalable MVC architecture in PHP8 framework How to implement scalable MVC architecture in PHP8 framework Sep 11, 2023 pm 01:27 PM

How to implement a scalable MVC architecture in the PHP8 framework Introduction: With the rapid development of the Internet, more and more websites and applications adopt the MVC (Model-View-Controller) architecture pattern. The main goal of MVC architecture is to separate different parts of the application in order to improve the maintainability and scalability of the code. In this article, we will introduce how to implement a scalable MVC architecture in the PHP8 framework. 1. Understand the MVC architecture pattern. The MVC architecture pattern is a software design

How to use MVC architecture to design projects in PHP How to use MVC architecture to design projects in PHP Jun 27, 2023 pm 12:18 PM

In Web development, MVC (Model-View-Controller) is a commonly used architectural pattern for processing and managing an application's data, user interface, and control logic. As a popular web development language, PHP can also use the MVC architecture to design and build web applications. This article will introduce how to use MVC architecture to design projects in PHP, and explain its advantages and precautions. What is MVCMVC is a software architecture pattern commonly used in web applications. MV

Developing MVC with PHP8 framework: Important concepts and techniques that beginners need to know Developing MVC with PHP8 framework: Important concepts and techniques that beginners need to know Sep 11, 2023 am 09:43 AM

Developing MVC with PHP8 framework: Important concepts and techniques that beginners need to know Introduction: With the rapid development of the Internet, Web development plays an important role in today's software development industry. PHP is widely used for web development, and there are many mature frameworks that help developers build applications more efficiently. Among them, the MVC (Model-View-Controller) architecture is one of the most common and widely used patterns. This article will introduce how beginners can use the PHP8 framework to develop MVC applications.

Revealing the secrets of PHP MVC architecture: Make your website fly Revealing the secrets of PHP MVC architecture: Make your website fly Mar 03, 2024 am 09:25 AM

Model-view-controller (mvc) architecture is a powerful design pattern for building maintainable and scalable WEB applications. The PHPMVC architecture decomposes application logic into three distinct components: Model: represents the data and business logic in the application. View: Responsible for presenting data to users. Controller: Acts as a bridge between the model and the view, handling user requests and coordinating other components. Advantages of MVC architecture: Code separation: MVC separates application logic from the presentation layer, improving maintainability and scalability. Reusability: View and model components can be reused across different applications, reducing code duplication. Performance Optimization: MVC architecture allows caching of view and model results, thus increasing website speed. Test Friendly: Detachment

See all articles