php制作简单模版引擎


Posted in PHP onApril 07, 2016

PHP模板引擎就是一个PHP类库,使用它可以使PHP代码和HTML代码进行分离,使代码的可读性和维护性得到显著提高。而且这样做的好处是,让美工专心设计HTML前台页面,程序员专心去写PHP业务逻辑。因此,模化引擎很适合公司的Web开发团队使用,使每个人都能发挥其特长

下面我们就来看看如何简单的来实现php的模板引擎

parser.class.php

<?php
 
/**
 * 模版解析类
 */
class Parser
{
  // 字段,接收模版文件内容
  private $_tpl;
   
  // 构造方法,获取模版文件内容
  public function __construct($_tplFile)
  {
    if (! $this->_tpl = file_get_contents($_tplFile)) {
      exit('ERROR:模版文件读取错误');
    }
  }
   
  // 解析普通变量
  private function parvar()
  {
    $_patten = '/<!--\s+\{\$([\w]+)\}\s+-->/';
    if (preg_match($_patten,$this->_tpl)) {
      $this->_tpl = preg_replace($_patten, "<?php echo \$this->_vars['$1'];?>",$this->_tpl);
    }
  }
 
  //解析IF语句
  private function parif(){
    $_pattenif = '/<!--\s+\{if\s+\$([\w]+)\}\s+-->/';
    $_pattenElse = '/<!--\s+\{else\}\s+-->/';
    $_pattenEndif = '/<!--\s+\{\/if\}\s+-->/';
    if (preg_match($_pattenif,$this->_tpl)) {
      if (preg_match($_pattenEndif,$this->_tpl)) {
        $this->_tpl = preg_replace($_pattenif,"<?php if (\$this->_vars['$1']){?>",$this->_tpl);
        $this->_tpl = preg_replace($_pattenEndif,"<?php } ?>",$this->_tpl);
        if (preg_match($_pattenElse,$this->_tpl)) {
          $this->_tpl = preg_replace($_pattenElse,"<?php }else{?>",$this->_tpl);
        }
      }else{
      echo 'ERROR:IF语句没有关闭!';
      }
    }
  }
 
  //PHP注释解析
 
  private function parCommon(){
    $_pattenCommon = '/<!--\s+\{#\}(.*)\{#\}\s+-->/';
    if (preg_match($_pattenCommon,$this->_tpl)) {
      $this->_tpl = preg_replace($_pattenCommon,"<?php /* $1 */ ?>",$this->_tpl);
    }
  }
   
  //解析foreach语句
  private function parForeach(){
    $_pattenForeach = '/<!--\s+\{foreach\s+\$([\w]+)\(([\w]+),([\w]+)\)\}\s+-->/';
    $_pattenForeachEnd = '/<!--\s+\{\/foreach\}\s+-->/';
    $_pattenForeachValue = '/<!--\s+\{@([\w]+)\}\s+-->/';
    if (preg_match($_pattenForeach,$this->_tpl)) {
      if (preg_match($_pattenForeachEnd,$this->_tpl)) {
        $this->_tpl = preg_replace($_pattenForeach, "<?php foreach (\$this->_vars['$1'] as \$$2=>\$$3) {?>", $this->_tpl);
        $this->_tpl = preg_replace($_pattenForeachEnd, "<?php }?>", $this->_tpl);
        if (preg_match($_pattenForeachValue, $this->_tpl)) {
          $this->_tpl = preg_replace($_pattenForeachValue,"<?php echo \$$1;?>",$this->_tpl);
        }
      }else{
      echo 'ERROR:Foreach语句没有关闭!';  
      }
    }
  }
 
  //解析include方法
  private function parInclude(){
    $_pattenInclude = '/<!--\s+\{include\s+file=\"([\w\.\-]+)\"\}\s+-->/';
    if (preg_match($_pattenInclude,$this->_tpl,$_file,$_file)) {
      if (!file_exists($_file[1])||empty($_file)) {
        echo 'ERROR:包含文件出错!';
      }
      $this->_tpl = preg_replace($_pattenInclude,"<?php include '$1';?>",$this->_tpl);
    }
  }
 
  //解析系统变量方法
  private function parConfig(){
    $_pattenConfig = '/<!--\s+\{([\w]+)\}\s+-->/';
    if (preg_match($_pattenConfig,$this->_tpl)) {
      $this->_tpl = preg_replace($_pattenConfig,"<?php echo \$this->_config['$1'];?>",$this->_tpl);
    }
  }
  // 对外公共方法
  public function compile($_path)
  {
    // 解析模版文件
    $this->parvar();
    $this->parif();
    $this->parForeach();
    $this->parInclude();
    $this->parCommon();
    $this->parConfig();
    // 生成编译文件
    if (! file_put_contents($_path, $this->_tpl)) {
      exit('ERROR:编译文件生成错误!');
    }
  }
}
?>

Templates.class.php

<?php
 
/**
 * 模版类
 */
class Templates
{
  //注入变量
  private $_vars = array();
  //保存系统变量数组字段
  private $_config = array();
  //创建一个构造方法,来检测各个目录是否存在
  public function __construct()
  {
    if (! is_dir(TPL_DIR) || ! is_dir(TPL_C_DIR) || ! is_dir(CACHE) || !is_dir(CONFIG)) {
      echo 'ERROR:模版目录或编译目录,缓存目录不存在!自动创建!'."<br />";
      if (!is_dir(TPL_DIR)) {
        mkdir(TPL_DIR);
        echo '模版目录'.TPL_DIR.'建立'."<br />";
      }
      if (!is_dir(TPL_C_DIR)) {
        mkdir(TPL_C_DIR);
        echo '编译目录'.TPL_C_DIR.'建立'."<br />";
      }
      if (!is_dir(CACHE)) {
        mkdir(CACHE);
        echo '缓存目录'.CACHE.'建立'."<br />";
      }
      if (!is_dir(CONFIG)) {
        mkdir(CONFIG);
        echo '缓存目录'.CONFIG.'建立'."<br />";
      }
      exit();
    }
    //保存系统变量
    $_sxe = simplexml_load_file(CONFIG.'/config.xml');
    $_tagLib = $_sxe->xpath('/root/taglib');
    foreach ($_tagLib as $_tag) {
      $this->_config["$_tag->name"] = $_tag->value;
    }
  }
 
  //assign()方法,用于注入变量
  public function assign($_var,$_value){
    //$_var用于同步模版里的变量名
    //$_value表示值
    if (isset($_var)&&!empty($_var)) {
      $this->_vars[$_var] = $_value;
    }else{
      exit('ERROR:设置模版变量!');
    }
 
  }
 
  //display()方法
  public function display($_file)
  {
    $_tplFile = TPL_DIR . $_file;
    // 判断文件是否存在
    if (! file_exists($_tplFile)) {
      echo 'ERROR:模版文件不存在!自动创建Index.tpl模版文件!';
      file_put_contents($_tplFile,'Index');
      exit();
    }
 
    //生成编译文件
    $_path = TPL_C_DIR.md5($_file).'-'.$_file.'.php';
    //缓存文件
    $_cacheFile = CACHE.md5($_file).'-'.$_file.'.html';
    //当第二次运行相同文件,直接载入缓存文件
    if (IS_CACHE) {
      //判断缓存文件和编译文件都存在
      if (file_exists($_cacheFile)&&file_exists($_path)) {
        //判断模版文件是否修改过
        if (filemtime($_path)>=filemtime($_tplFile)&&filemtime($_cacheFile)>=filemtime($_path)) {
          include $_cacheFile;
          echo '<!--cache-->';
          return;
        }
      }
    }
    //当编译文件不存在或者文件发生改变则重新生成
    if (!file_exists($_path)||filemtime($_path)<filemtime($_tplFile)) {
      require ROOT_PATH.'/Class/parser.class.php';
      //构造方法是传入模版文件地址
      $_parser = new Parser($_tplFile);
      //传入编译文件地址
      $_parser->compile($_path);
    }
    //载入编译文件
    include $_path;
    if (IS_CACHE) {
      //获取缓冲区数据
      file_put_contents($_cacheFile,ob_get_contents());
      //清楚缓冲区
      ob_end_clean();
      //载入缓存文件
      include $_cacheFile;
    }
  }
}
?>

templates.php

<?php
//设置字符编码UTF-8
header('Content-Type:text/html;charset=utf-8');
 
//网站根目录
define('ROOT_PATH',dirname(__FILE__));
 
//存放模版文件夹
define('TPL_DIR',ROOT_PATH.'/Templates/');
 
//编译文件夹
define('TPL_C_DIR',ROOT_PATH.'/Templates_c/');
 
//缓存文件夹
define('CACHE',ROOT_PATH.'/Cache/');
 
//系统变量配置目录
define('CONFIG',ROOT_PATH.'/Config/');
 
//是否开启缓冲区
define('IS_CACHE',false);//false
 
//判断是否需要开启
IS_CACHE ? ob_start() : null;
 
//引入模版类
require ROOT_PATH.'/Class/Templates.class.php';
 
//实例化模版类
$_tpl=new Templates();
 
$_tpl->display('index.tpl');
?>

templates/index.tpl

<!DOCTYPE html>
<html lang="zn-cn">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
  <meta name="description" content="">
  <meta name="keywords" content="">
  <meta name="author" content="">
  <meta name="author" content="">
  <title><!-- {WebName} --></title>
  <link rel="stylesheet" type="text/css" href="css/bootstrap.min.css">
  <link rel="stylesheet" type="text/css" href="css/style.css">
  </head>
<body>
 
<!-- {#}php注释{#} -->
<!-- {if $a} -->
123
<!-- {else} -->
321
<!-- {/if} -->
<br />
<!-- {foreach $array(key,value)} -->
  <!-- {@key} -->...<!-- {@value} --><br />
<!-- {/foreach} -->
系统变量<!-- {WebName} --><br />
普通变量<!-- {$name} --><br />

  <script src="/js/jquery-2.2.1.min.js" type="text/javascript"></script>
  <script src="/js/bootstrap.min.js" type="text/javascript"></script>
  <script type="text/javascript">
  </script>
</body>
</html>

config/config.xml

<?xml version="1.0" encoding="UTF-8"?>
<root>
  <taglib>
    <name>WebName</name>
    <value>XXX网站</value>
  </taglib>
</root>
PHP 相关文章推荐
基于mysql的论坛(1)
Oct 09 PHP
如何使用脚本模仿登陆过程
Nov 22 PHP
Linux下ZendOptimizer的安装与配置方法
Apr 12 PHP
Optimizer与Debugger兼容性问题的解决方法
Dec 01 PHP
destoon实现资讯信息前面调用它所属分类的方法
Jul 15 PHP
教你如何开启shopnc b2b2c 伪静态
Oct 21 PHP
php跨站攻击实例分析
Oct 28 PHP
php商品对比功能代码分享
Sep 24 PHP
深入理解PHP中的empty和isset函数
May 26 PHP
基于ThinkPHP实现的日历功能实例详解
Apr 15 PHP
PHP使用xpath解析XML的方法详解
May 20 PHP
详解php 使用Callable Closure强制指定回调类型
Oct 26 PHP
thinkphp框架下实现登录、注册、找回密码功能
Apr 06 #PHP
非常有用的9个PHP代码片段
Apr 06 #PHP
10个对初学者非常有用的PHP技巧
Apr 06 #PHP
yii2.0实现pathinfo的形式访问的配置方法
Apr 06 #PHP
PHP实现的DES加密解密实例代码
Apr 06 #PHP
php使用正则验证中文
Apr 06 #PHP
php HTML无刷新提交表单
Apr 05 #PHP
You might like
smarty内置函数foreach用法实例
2015/01/22 PHP
eclipse php wamp配置教程
2016/06/30 PHP
PHP redis实现超迷你全文检索
2017/03/04 PHP
重定向实现代码
2006/11/20 Javascript
csdn 博客中实现运行代码功能实现
2009/08/29 Javascript
鼠标选择动态改变网页背景颜色的JS代码
2013/12/10 Javascript
通过伪协议解决父页面与iframe页面通信的问题
2015/04/05 Javascript
Express实现前端后端通信上传图片之存储数据库(mysql)傻瓜式教程(二)
2015/12/10 Javascript
Jquery和JS获取ul中li标签的实现方法
2016/06/02 Javascript
Vue.js项目模板搭建图文教程
2017/09/20 Javascript
JavaScript多线程运行库Nexus.js详解
2017/12/22 Javascript
js保留两位小数方法总结
2018/01/31 Javascript
JS实现长图上下滚动效果
2020/03/19 Javascript
Node.js API详解之 os模块用法实例分析
2020/05/06 Javascript
vue-video-player实现实时视频播放方式(监控设备-rtmp流)
2020/08/10 Javascript
原生js实现弹幕效果
2020/11/29 Javascript
JS canvas实现画板和签字板功能
2021/02/23 Javascript
Python字典操作简明总结
2015/04/13 Python
Python实现的NN神经网络算法完整示例
2018/06/19 Python
python中将zip压缩包转为gz.tar的方法
2018/10/18 Python
python如何实现异步调用函数执行
2019/07/08 Python
简单了解django索引的相关知识
2019/07/17 Python
html2canvas把div保存图片高清图的方法示例
2018/03/05 HTML / CSS
HTML5开发动态音频图的实现
2020/07/02 HTML / CSS
任意存:BOXFUL
2018/05/21 全球购物
史上最全面的Java面试题汇总!
2015/02/03 面试题
司机辞职报告范文
2014/01/20 职场文书
学校师德承诺书
2014/05/23 职场文书
运动会演讲稿300字
2014/08/25 职场文书
机电专业毕业生自我鉴定2014
2014/10/04 职场文书
预备党员群众路线教育实践活动思想汇报2014
2014/10/25 职场文书
2014年街道办事处工作总结
2014/12/11 职场文书
小学教师个人总结
2015/02/05 职场文书
教师学期末个人总结
2015/02/13 职场文书
MySQL 中如何归档数据的实现方法
2022/03/16 SQL Server
Java8利用Stream对列表进行去除重复的方法详解
2022/04/14 Java/Android