PHP如何实现模板解析类
创始人
2024-12-11 16:21:42
0次

具体如下:

';//模板右标签
 private $template_c = '';//编译目录
 private $template_path = '';//模板完整路径 
 private $template_name = '';//模板名称 index.html
 //定义每个模板的标签的元素
 private $tag_foreach = array('from', 'item', 'key');
 private $tag_include = array('file');//目前只支持读取模板默认路径
 public function __construct($conf) {
  $this->conf = &$conf;
  $this->template_c = $this->conf['template_config']['template_c'];//编译目录
  $this->_tpl_suffix = $this->tpl_suffix();
 }
 private function str_replace($search, $replace, $content) {
  if(empty($search) || empty($replace) || empty($content)) return false;
  return str_replace($search, $replace, $content);
 }
 /**
  * preg_match_all
  * @param $pattern 正则
  * @param $content 内容
  * @return array
  */
 private function preg_match_all($pattern, $content) {
  if(empty($pattern) || empty($content)) core::show_error('查找模板标签失败!');
  preg_match_all("/".$this->template_tag_left.$pattern.$this->template_tag_right."/is", $content, $match);
  return $match;
 }
 /**
  * 模板文件后缀 
  */
 public function tpl_suffix() {
  $tpl_suffix = empty($this->conf['template_config']['template_suffix']) ? 
       $this->tpl_suffix : 
       $this->conf['template_config']['template_suffix'] ;
  return $tpl_suffix;
 }
 /**
  * 此处不解释了
  * @return 
  */
 public function assign($key, $value) {
  $this->vars[$key] = $value;
 }
 /**
  * 渲染页面
  * @param 
  * 使用方法 1
  * $this->view->display('error', 'comm/');
  * 默认是指向TPL模版的跟目录,所以comm/就是 tpl/comm/error.html
  * 使用方法 2
  * $this->view->display('errorfile'); 
  * 默认指向控制器固定的文件夹
  * 例如你的域名是 http://heartphp/admin/index, 那么正确路径就是tpl/admin/index/errorfile.html
  * @return 
  */
 public function display($filename = '', $view_path = '') {
  $tpl_path_arr = $this->get_tpl($filename, $view_path);//获取TPL完整路径 并且向指针传送路径以及名称
  if(!$tpl_path_arr) core::show_error($filename.$this->_tpl_suffix.'模板不存在');
  //编译开始
  $this->view_path_param = $view_path;//用户传递过来的模版跟目录
  $this->compile();
 }
 /**
  * 编译控制器
  * @param 
  * @return 
  */
 private function compile() {
  $filepath = $this->template_path.$this->template_name;
  $compile_dirpath = $this->check_temp_compile();
  $vars_template_c_name = str_replace($this->_tpl_suffix, '', $this->template_name);
  $include_file = $this->template_replace($this->read_file($filepath), $compile_dirpath, $vars_template_c_name);//解析
  if($include_file) {
   $this->read_config() && $config = $this->read_config();
   extract($this->vars, EXTR_SKIP);
   [url=home.php?mod=space&uid=48608]@include[/url] $include_file;
  }
 }
 /**
  * 读取当前项目配置文件
  */
 protected function read_config() {
  if(file_exists(SYSTEM_PATH.'conf/config.php')) {
   @include SYSTEM_PATH.'conf/config.php'; 
   return $config;
  }
  return false;
 }
 /**
  * 解析模板语法
  * @param $str 内容
  * @param $compile_dirpath 模版编译目录
  * @param $vars_template_c_name 模版编译文件名
  * @return 编译过的PHP模板文件名
  */
 private function template_replace($str, $compile_dirpath, $vars_template_c_name) {
  if(empty($str)) core::show_error('模板内容为空!');
  //处理编译头部
  $compile_path = $compile_dirpath.$vars_template_c_name.$this->tpl_compile_suffix;//编译文件
  if(is_file($compile_path)) {
   //$header_content = $this->get_compile_header($compile_path);
   //$compile_date = $this->get_compile_header_comment($header_content);
   $tpl_filemtime = filemtime($this->template_path.$this->template_name);
   $compile_filemtime = filemtime($compile_path);
   //echo $tpl_filemtime.'=='.date('Y-m-d H:i:s', $tpl_filemtime).'
';    //echo $compile_filemtime.'=='.date('Y-m-d H:i:s', $compile_filemtime);    //如果文件过期编译 当模板标签有include并且有修改时 也重新编译    //<{include file="public/left.html"}> 当修改include里的文件,非DEBUG模式时 如果不更改主文件 目前是不重新编译include里的文件,我在考虑是否也要更改,没想好,暂时这样,所以在开发阶段一定要开启DEBUG=1模式 要不然修改include文件无效 。 有点罗嗦,不知道表述清楚没    if($tpl_filemtime > $compile_filemtime || DEBUG) {     $ret_file = $this->compile_file($vars_template_c_name, $str, $compile_dirpath);    } else {     $ret_file = $compile_path;    }   } else {//编译文件不存在 创建他    $ret_file = $this->compile_file($vars_template_c_name, $str, $compile_dirpath);   }   return $ret_file;  }  /**   * 模板文件主体   * @param string $str 内容   * @return html   */  private function body_content($str) {   //解析   $str = $this->parse($str);   $header_comment = "Create On##".time()."|Compiled from##".$this->template_path.$this->template_name;   $content = "\r\n$str";   return $content;  }  /**   * 开始解析相关模板标签   * @param $content 模板内容   */  private function parse($content) {   //foreach   $content = $this->parse_foreach($content);   //include   $content = $this->parse_include($content);   //if   $content = $this->parse_if($content);   //elseif   $content = $this->parse_elseif($content);   //模板标签公用部分   $content = $this->parse_comm($content);    //转为PHP代码   $content = $this->parse_php($content);   return $content;  }  /**   * echo 如果默认直接<{$config['domain']}> 转成    */  private function parse_echo($content) {  }  /**   * 转换为PHP   * @param $content html 模板内容   * @return html 替换好的HTML   */  private function parse_php($content){   if(empty($content)) return false;   $content = preg_replace("/".$this->template_tag_left."(.+?)".$this->template_tag_right."/is", "", $content);   return $content;  }  /**   * if判断语句   * <{if empty($zhang)}>   * zhang   * <{elseif empty($liang)}>   * liang   * <{else}>   * zhangliang   * <{/if}>   */  private function parse_if($content) {   if(empty($content)) return false;   //preg_match_all("/".$this->template_tag_left."if\s+(.*?)".$this->template_tag_right."/is", $content, $match);   $match = $this->preg_match_all("if\s+(.*?)", $content);   if(!isset($match[1]) || !is_array($match[1])) return $content;   foreach($match[1] as $k => $v) {    //$s = preg_split("/\s+/is", $v);    //$s = array_filter($s);    $content = str_replace($match[0][$k], "", $content);   }   return $content;  }  private function parse_elseif($content) {   if(empty($content)) return false;   //preg_match_all("/".$this->template_tag_left."elseif\s+(.*?)".$this->template_tag_right."/is", $content, $match);   $match = $this->preg_match_all("elseif\s+(.*?)", $content);   if(!isset($match[1]) || !is_array($match[1])) return $content;   foreach($match[1] as $k => $v) {    //$s = preg_split("/\s+/is", $v);    //$s = array_filter($s);    $content = str_replace($match[0][$k], "", $content);   }   return $content;  }  /**   * 解析 include include标签不是实时更新的 当主体文件更新的时候 才更新标签内容,所以想include生效 请修改一下主体文件   * 记录一下 有时间开发一个当DEBUG模式的时候 每次执行删除模版编译文件   * 使用方法 <{include file="www.phpddt.com"}>   * @param $content 模板内容   * @return html   */  private function parse_include($content) {   if(empty($content)) return false;   //preg_match_all("/".$this->template_tag_left."include\s+(.*?)".$this->template_tag_right."/is", $content, $match);   $match = $this->preg_match_all("include\s+(.*?)", $content);   if(!isset($match[1]) || !is_array($match[1])) return $content;   foreach($match[1] as $match_key => $match_value) {    $a = preg_split("/\s+/is", $match_value);    $new_tag = array();    //分析元素    foreach($a as $t) {     $b = explode('=', $t);     if(in_array($b[0], $this->tag_include)) {      if(!empty($b[1])) {       $new_tag[$b[0]] = str_replace("\"", "", $b[1]);      } else {       core::show_error('模板路径不存在!');      }     }    }    extract($new_tag);    //查询模板文件    foreach($this->conf['view_path'] as $v){     $conf_view_tpl = $v.$file;//include 模板文件     if(is_file($conf_view_tpl)) {      $c = $this->read_file($conf_view_tpl);      $inc_file = str_replace($this->_tpl_suffix, '', basename($file));      $this->view_path_param = dirname($file).'/';      $compile_dirpath = $this->check_temp_compile();      $include_file = $this->template_replace($c, $compile_dirpath, $inc_file);//解析      break;     } else {      core::show_error('模板文件不存在,请仔细检查 文件:'. $conf_view_tpl);     }    }     $content = str_replace($match[0][$match_key], '', $content);   }   return $content;  }  /**   * 解析 foreach   * 使用方法 <{foreach from=$lists item=value key=kk}>   * @param $content 模板内容   * @return html 解析后的内容   */  private function parse_foreach($content) {   if(empty($content)) return false;   //preg_match_all("/".$this->template_tag_left."foreach\s+(.*?)".$this->template_tag_right."/is", $content, $match);   $match = $this->preg_match_all("foreach\s+(.*?)", $content);   if(!isset($match[1]) || !is_array($match[1])) return $content;   foreach($match[1] as $match_key => $value) {    $split = preg_split("/\s+/is", $value);    $split = array_filter($split);    $new_tag = array();    foreach($split as $v) {     $a = explode("=", $v);     if(in_array($a[0], $this->tag_foreach)) {//此处过滤标签 不存在过滤      $new_tag[$a[0]] = $a[1];     }    }    $key = '';    extract($new_tag);    $key = ($key) ? '$'.$key.' =>' : '' ;    $s = '';    $content = $this->str_replace($match[0][$match_key], $s, $content);   }   return $content;  }  /**   * 匹配结束 字符串   */  private function parse_comm($content) {   $search = array(    "/".$this->template_tag_left."\/foreach".$this->template_tag_right."/is",    "/".$this->template_tag_left."\/if".$this->template_tag_right."/is",    "/".$this->template_tag_left."else".$this->template_tag_right."/is",   );   $replace = array(    "",    "",    ""   );   $content = preg_replace($search, $replace, $content);   return $content;  }  /**   * 检查编译目录 如果没有创建 则递归创建目录   * @param string $path 文件完整路径   * @return 模板内容   */  private function check_temp_compile() {   //$paht = $this->template_c.   $tpl_path = ($this->view_path_param) ? $this->view_path_param : $this->get_tpl_path() ;   $all_tpl_apth = $this->template_c.$tpl_path;   if(!is_dir($all_tpl_apth)) {    $this->create_dir($tpl_path);   }   return $all_tpl_apth;  }  /**   * 读文件   * @param string $path 文件完整路径   * @return 模板内容   */  private function read_file($path) {   //$this->check_file_limits($path, 'r');   if(($r = @fopen($path, 'r')) === false) {    core::show_error('模版文件没有读取或执行权限,请检查!');   }   $content = fread($r, filesize($path));   fclose($r);   return $content;  }  /**   * 写文件   * @param string $filename 文件名   * @param string $content 模板内容   * @return 文件名   */  private function compile_file($filename, $content, $dir) {   if(empty($filename)) core::show_error("{$filename} Creation failed");   $content = $this->body_content($content);//对文件内容操作   //echo '开始编译了=====';   $f = $dir.$filename.$this->tpl_compile_suffix;   //$this->check_file_limits($f, 'w');   if(($fp = @fopen($f, 'wb')) === false) {    core::show_error($f.'
编译文件失败,请检查文件权限.');   }   //开启flock   flock($fp, LOCK_EX + LOCK_NB);   fwrite($fp, $content, strlen($content));   flock($fp, LOCK_UN + LOCK_NB);   fclose($fp);   return $f;  }  /**   * 这个检查文件权限函数 暂时废弃了   * @param [$path] [路径]   * @param [status] [w=write, r=read]   */  public function check_file_limits($path , $status = 'rw') {   clearstatcache();   if(!is_writable($path) && $status == 'w') {    core::show_error("{$path}
没有写入权限,请检查.");   } elseif(!is_readable($path) && $status == 'r') {    core::show_error("{$path}
没有读取权限,请检查.");   } elseif($status == 'rw') {//check wirte and read    if(!is_writable($path) || !is_readable($path)) {     core::show_error("{$path}
没有写入或读取权限,请检查");    }   }  }  /**   * 读取编译后模板的第一行 并分析成数组   * @param string $filepath 文件路径   * @param number $line  行数   * @return 返回指定行数的字符串    */  /*  private function get_compile_header($filepath, $line = 0) {   if(($file_arr = @file($filepath)) === false) {    core::show_error($filepath.'
读取文件失败,请检查文件权限!');   }   return $file_arr[0];  }  */  /**   * 分析头部注释的日期   * @param string $cotnent 编译文件头部第一行   * @return 返回上一次日期    */  /*  private function get_compile_header_comment($content) {   preg_match("/\/\*(.*?)\*\//", $content, $match);   if(!isset($match[1]) || empty($match[1])) core::show_error('编译错误!');    $arr = explode('|', $match[1]);   $arr_date = explode('##', $arr[0]);   return $arr_date[1];  }  */  /**   * 获取模板完整路径 并返回已存在文件   * @param string $filename 文件名   * @param string $view_path 模板路径    * @return    */  private function get_tpl($filename, $view_path) {   empty($filename) && $filename = $this->tpl_name;   //遍历模板路径   foreach($this->conf['view_path'] as $path) {    if($view_path) {//直接从tpl跟目录找文件     $tpl_path = $path.$view_path;     $view_file_path = $tpl_path.$filename.$this->_tpl_suffix;    } else {//根据目录,控制器,方法开始找文件     $view_file_path = ($tpl_path = $this->get_tpl_path($path)) ? $tpl_path.$filename.$this->_tpl_suffix : exit(0);    }    if(is_file($view_file_path)) {     //向指针传送模板路径和模板名称     $this->template_path = $tpl_path;//     $this->template_name = $filename.$this->_tpl_suffix;     return true;    } else {     core::show_error($filename.$this->_tpl_suffix.'模板不存在');    }   }  }  /**   * 获取模板路径   * @param string $path 主目录   * @return URL D和M的拼接路径   */  private function get_tpl_path($path = '') {   core::get_directory_name() && $path_arr[0] = core::get_directory_name();   core::get_controller_name() && $path_arr[1] = core::get_controller_name();   (is_array($path_arr)) ? $newpath = implode('/', $path_arr) : core::show_error('获取模板路径失败!') ;   return $path.$newpath.'/';  }  /**   * 创建目录   * @param string $path 目录   * @return    */  private function create_dir($path, $mode = 0777){   if(is_dir($path)) return false;   $dir_arr = explode('/', $path);   $dir_arr = array_filter($dir_arr);   $allpath = '';   $newdir = $this->template_c;   foreach($dir_arr as $dir) {    $allpath = $newdir.'/'.$dir;    if(!is_dir($allpath)) {     $newdir = $allpath;     if(!@mkdir($allpath, $mode)) {      core::show_error( $allpath.'
创建目录失败,请检查是否有可都写权限!');     }     chmod($allpath, $mode);    } else {     $newdir = $allpath;    }   }   return true;  }  public function __destruct(){   $this->vars = null;   $this->view_path_param = null;  } }

相关内容

热门资讯

空调连续工作多久需要停机休息 空调连续工作的时间取决于多个因素,包括空调的型号、功率、使用环境和维护情况等。一般来说,空调可以连续...
空调哪个符号是除湿的 空调除湿功能通常用一个水滴形状的符号表示。不同品牌和型号的空调遥控器可能会有所差异,但一般来说,除湿...
格力空调多长时间加一次氟利昂 1、一般情况下,空调对氟利昂的使用量是非常小的,所以在空调使用了四年左右的时候再考虑加也没问题。2、...
空调用多长时间需要加氟一次 一般情况下是五年。当出现以下这几种情况时,空调才需要加氟。1、空调的室内机和室外机各有两个接口,当接...
格调生活·C标思享荟:卡萨帝在... 9月12日的郑州龙湖金融岛,夜风轻拂,灯光璀璨。“C标时刻共传奇——卡萨帝思享荟暨20周年品牌盛典郑...
品牌价值破千亿、高端份额持续领... 9月12日,“C标时刻共传奇——卡萨帝思享荟暨20周年品牌盛典郑州站”在郑州龙湖金融岛举办。2026...
空调主板坏了修800还是换新的 空调主板坏了是修还是换新,需要考虑多个因素,以下是一些建议:1. 维修成本:如果维修费用较低,比如 ...
空调开多久需要休息多长时间 问题:空调开多久需要休息多长时间回答:1、在使用空调的过程中,一般空调开7~8个小时左右需要休息2~...
中央空调多长时间清洗一次 1、一般空调开机前清洗一次即可,空调开机中间时段再清洗一次,空调关机时清洗一次,这样比较合理。2、空...
中央空调氟利昂多久加一次 看空调制热和制冷程度,很多人的观点认为氟利昂必须一年放一次,其实这个观点是错误的,理解上面有点偏差,...