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 相关文章推荐
桌面中心(四)数据显示
Oct 09 PHP
一些关于PHP的知识
Nov 17 PHP
在普通HTTP上安全地传输密码
Jul 21 PHP
PHP下打开URL地址的几种方法小结
May 16 PHP
PHP学习之字符串比较和查找
Apr 17 PHP
php实现rc4加密算法代码
Apr 25 PHP
解析PHP无限级分类方法及代码
Jun 21 PHP
浅析ThinkPHP缓存之快速缓存(F方法)和动态缓存(S方法)(日常整理)
Oct 26 PHP
PHP生成和获取XML格式数据的方法
Mar 04 PHP
PHP页面输出搜索后跳转下一页的处理方法
Sep 30 PHP
PHP 访问数据库配置通用方法(json)
May 20 PHP
PHP终止脚本运行三种实现方法详解
Sep 01 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
js 表单验证方法(实用)
2009/04/28 Javascript
Javascript的各种节点操作实例演示代码
2012/06/27 Javascript
eval的两组性能测试数据
2012/08/17 Javascript
Extjs优化(一)删除冗余代码提高运行速度
2013/04/15 Javascript
JS正则表达式验证数字代码
2014/01/28 Javascript
JS版的date函数(和PHP的date函数一样)
2014/05/12 Javascript
javascript无刷新评论实现方法
2015/05/13 Javascript
JS实现上下左右对称的九九乘法表
2016/02/22 Javascript
jQuery插件ImgAreaSelect实现头像上传预览和裁剪功能实例讲解一
2017/05/26 jQuery
vue.js 获取当前自定义属性值
2017/06/01 Javascript
JavaScript用200行代码制作打飞机小游戏实例
2017/06/21 Javascript
基于Vue实现支持按周切换的日历
2020/09/24 Javascript
JavaScript实现的超简单计算器功能示例
2017/12/23 Javascript
vue 自定义全局方法,在组件里面的使用介绍
2018/02/28 Javascript
详解angular如何调用HTML字符串的方法
2018/06/30 Javascript
Angular事件之不同组件间传递数据的方法
2018/11/15 Javascript
[00:28]DOTA2北京网鱼队选拔赛
2015/04/08 DOTA
Python写的一个简单监控系统
2015/06/19 Python
python和flask中返回JSON数据的方法
2018/03/26 Python
Django框架 querySet功能解析
2019/09/04 Python
Django 返回json数据的实现示例
2020/03/05 Python
Python3 xml.etree.ElementTree支持的XPath语法详解
2020/03/06 Python
利用CSS3实现圆角的outline效果的教程
2015/06/05 HTML / CSS
关于老式浏览器兼容HTML5和CSS3的问题
2016/06/01 HTML / CSS
洛杉矶生活休闲而精致的基础品牌:Mika Jaymes
2018/01/07 全球购物
Bibloo匈牙利:女装、男装、童装及鞋子和配饰
2019/04/14 全球购物
毕业生多媒体设计求职信
2013/10/12 职场文书
《美丽的田园》教学反思
2014/03/01 职场文书
现场施工员岗位职责
2014/03/10 职场文书
应届大专毕业生自我鉴定
2014/04/08 职场文书
交通安全标语
2014/06/06 职场文书
小学班级特色活动方案
2014/08/31 职场文书
2015年上半年物业工作总结
2015/03/30 职场文书
新学期主题班会
2015/08/17 职场文书
JS Canvas接口和动画效果大全
2021/04/29 Javascript
Python机器学习之KNN近邻算法
2021/05/14 Python