简单的自定义php模板引擎

模板引擎的思想是来源于MVC(Model View Controller)模型,即模型层、视图层、控制器层。

在Web端,模型层为数据库的操作;视图层就是模板,也就是Web前端;Controller就是PHP对数据和请求的各种操作。模板引擎就是为了将视图层和其他层分离开来,使php代码和html代码不会混杂在一起。因为当php代码和html代码混杂在一起时,将使代码的可读性变差,并且代码后期的维护会变得很困难。

大部分的模板引擎原理都差不多,核心就是利用正则表达式解析模板,将约定好的特定的标识语句编译成php语句,然后调用时只需要include编译后的文件,这样就讲php语句和html语句分离开来了。甚至可以更进一步将php的输出输出到缓冲区,然后将模板编译成静态的html文件,这样请求时,就是直接打开静态的html文件,请求速度大大加快。

简单的自定义模板引擎就是两个类,第一个是模板类、第二个是编译类。

首先是编译类:

class CompileClass {
 private $template;  // 待编译文件
 private $content;  // 需要替换的文本
 private $compile_file;  // 编译后的文件
 private $left = '{';  // 左定界符
 private $right = '}';  // 右定界符
 private $include_file = array();  // 引入的文件
 private $config;  // 模板的配置文件
 private $T_P = array();  // 需要替换的表达式
 private $T_R = array();  // 替换后的字符串

 public function __construct($template, $compile_file, $config) {}

 public function compile() {
  $this->c_include();
  $this->c_var();
  $this->c_staticFile();
  file_put_contents($this->compile_file, $this->content);
 }

 // 处理include
 public function c_include() {}

 // 处理各种赋值和基本语句
 public function c_var() {}

 // 对静态的JavaScript进行解析
 public function c_staticFile() {}
}

编译类的大致结构就是上面那样,编译类的工作就是根据配置的文件,将写好的模板文件按照规则解析,替换然后输出到文件中。这个文件的内容是php和html混杂的,但在使用模板引擎进行开发时并不需要在意这个文件,因为我们要编写的是模板文件,也就是html和我们自己定义的标签混合的一个文件。这样View和其他两层就分离开来了。

在这个自定义模板引擎中,我的左右定界符就是大括号,具体的解析规则就是放在__construct()中

// 需要替换的正则表达式
$this->T_P[] = "/$this->left\s*\\$([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\xf7-\xff]*)\s*$this->right/";
$this->T_P[] = "/$this->left\s*(loop|foreach)\s*\\$([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\xf7-\xff]*)\s*$this->right/";
$this->T_P[] = "/$this->left\s*(loop|foreach)\s*\\$([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\xf7-\xff]*)\s+"
  . "as\s+\\$([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\xf7-\xff]*)$this->right/";
$this->T_P[] = "/$this->left\s*\/(loop|foreach|if)\s*$this->right/";
$this->T_P[] = "/$this->left\s*if(.*?)\s*$this->right/";
$this->T_P[] = "/$this->left\s*(else if|elseif)(.*?)\s*$this->right/";
$this->T_P[] = "/$this->left\s*else\s*$this->right/";
$this->T_P[] = "/$this->left\s*([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\xf7-\xff]*)\s*$this->right/";

// 替换后的字符串
$this->T_R[] = "<?php echo \$\\1; ?>";
$this->T_R[] = "<?php foreach((array)\$\\2 as \$K=>\$V) { ?>";
$this->T_R[] = "<?php foreach((array)\$\\2 as &\$\\3) { ?>";
$this->T_R[] = "<?php } ?>";
$this->T_R[] = "<?php if(\\1) { ?>";
$this->T_R[] = "<?php } elseif(\\2) { ?>";
$this->T_R[] = "<?php } else { ?>";
$this->T_R[] = "<?php echo \$\\1; ?>";

上面的解析规则包含了基本的输出和一些常用的语法,if、foreach等。利用preg_replace函数就能对模板文件进行替换。具体情况如下

<!--模板文件-->
{$data}
{foreach $vars}
 {if $V == 1 }
  <input value="{V}">
 {elseif $V == 2}
  <input value="123123">
 {else }
  <input value="sdfsas是aa">
 {/if}
{/foreach}

{ loop $vars as $var}
 <input value="{var}">
{ /loop }
 // 解析后
<?php echo $data; ?>
<?php foreach((array)$vars as $K=>$V) { ?>
 <?php if( $V == 1) { ?>
  <input value="<?php echo $V; ?>">
 <?php } elseif( $V == 2) { ?>
  <input value="123123">
 <?php } else { ?>
  <input value="sdfsas是aa">
 <?php } ?>
<?php } ?>

<?php foreach((array)$vars as &$var) { ?>
 <input value="<?php echo $var; ?>">
<?php } ?>

编译类的工作大致就是这样,剩下的include和对JavaScript的解析都和这个大同小异。

然后就是模板类

class Template {
 // 配置数组
 private $_arrayConfig = array(
  'root' => '',  // 文件根目录
  'suffix' => '.html',  // 模板文件后缀
  'template_dir' => 'templates',  // 模板所在文件夹
  'compile_dir' => 'templates_c',  // 编译后存放的文件夹
  'cache_dir' => 'cache',  // 静态html存放地址
  'cache_htm' => false,  // 是否编译为静态html文件
  'suffix_cache' => '.htm',  // 设置编译文件的后缀
  'cache_time' => 7200,  // 自动更新间隔
  'php_turn' => true,  // 是否支持原生php代码
  'debug' => 'false',
 );
 private $_value = array();
 private $_compileTool;  // 编译器
 static private $_instance = null;
 public $file;  // 模板文件名
 public $debug = array();  // 调试信息

 public function __construct($array_config=array()) {}

 // 单步设置配置文件
 public function setConfig($key, $value=null) {}

 // 注入单个变量
 public function assign($key, $value) {}

 // 注入数组变量
 public function assignArray($array) {}

 // 是否开启缓存
 public function needCache() {}

 // 如果需要重新编译文件
 public function reCache() {}

 // 显示模板
 public function show($file) {}

}

整个模板类的工作流程就是先实例化模板类对象,然后利用assign和assignArray方法给模板中的变量赋值,然后调用show方法,将模板和配置文件传入编译类的实例化对象中然后直接include编译后的php、html混编文件,显示输出。简单的流程就是这样,详细的代码如下

public function show($file) {
 $this->file = $file;
 if(!is_file($this->path())) {
  exit("找不到对应的模板文件");
 }

 $compile_file = $this->_arrayConfig['compile_dir']. md5($file). '.php';
 $cache_file = $this->_arrayConfig['cache_dir']. md5($file). $this->_arrayConfig['suffix_cache'];

 // 如果需要重新编译文件
 if($this->reCache($file) === false) {
  $this->_compileTool = new CompileClass($this->path(), $compile_file, $this->_arrayConfig);

  if($this->needCache()) {
   // 输出到缓冲区
   ob_start();
  }
  // 将赋值的变量导入当前符号表
  extract($this->_value, EXTR_OVERWRITE);

  if(!is_file($compile_file) or filemtime($compile_file) < filemtime($this->path())) {
   $this->_compileTool->vars = $this->_value;
   $this->_compileTool->compile();
   include($compile_file);
  }
  else {
   include($compile_file);
  }

  // 如果需要编译成静态文件
  if($this->needCache() === true) {
   $message = ob_get_contents();
   file_put_contents($cache_file, $message);
  }
 }
 else {
  readfile($cache_file);
 }
}

在show方法中,我首先判断模板文件存在,然后利用MD5编码生成编译文件和缓存文件的文件名。然后就是判断是否需要进行编译,判断的依据是看编译文件是否存在和编译文件的写入时间是否小于模板文件。如果需要编译,就利用编译类进行编译,生成一个php文件。然后只需要include这个编译文件就好了。

为了加快模板的载入,可以将编译后的文件输出到缓冲区中,也就是ob_start()这个函数,所有的输出将不会输出到浏览器,而是输出到默认的缓冲区,在利用ob_get_contents()将输出读取出来,保存成静态的html文件。

具体的使用如下

require('Template.php');

$config = array(
 'debug' => true,
 'cache_htm' => false,
 'debug' => true
);

$tpl = new Template($config);
$tpl->assign('data', microtime(true));
$tpl->assign('vars', array(1,2,3));
$tpl->assign('title', "hhhh");
$tpl->show('test');

缓存后的文件如下

<!DOCTYPE html>
<html>
 <head>
  <title>hhhh</title>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
 </head>
 <body>
  1466525760.32         <input value="1">
            <input value="123123">
            <input value="sdfsas是aa">

     <input value="1">
     <input value="2">
     <input value="3">
    <script src="123?t=1465898652"></script>
 </body>
</html>

一个简单的自定义模板引擎就完成了,虽然简陋但是能用,而且重点在于造轮子的乐趣和收获。 
完整代码可见我的 github

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • PHP原生模板引擎 最简单的模板引擎

    复制代码 代码如下: <?php $a = array( 'a','b','c' ); require 'template/demo.php';//引用模板 ?> 模板文件: 复制代码 代码如下: <!DOCTYPE html> <html lang="zh"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-

  • php模板引擎技术简单实现

    用了smarty,tp过后,也想了解了解其模板技术是怎么实现,于是写一个简单的模板类,大致就是读取模板文件->替换模板文件的内容->保存或者静态化 tpl.class.php主要解析 assign 方法实现 /** * 模板赋值操作 * @param mixed $tpl_var 如果是字符串,就作为数组索引,如果是数组,就循环赋值 * @param mixed $tpl_value 当$tpl_var为string时的值,默认为 null */ public function assign(

  • php smarty模板引擎的6个小技巧

    下面本文将以具体的例子一一分析: capture标签 capture的中文意思是抓取,它的作用是抓取模板输出的数据,当我们需要它的时候,调用它,以得到抓取数据的目的.如下例子: 复制代码 代码如下: {capture name="test"} <img src="testimg.jpg"> {/capture} <div class="image"> {$smarty.capture.test} </div>

  • Pain 全世界最小最简单的PHP模板引擎 (普通版)

    打包下载 Pain.php 复制代码 代码如下: <?php class Pain { public $var=array(); public $tpl=array(); //this is the method to assign vars to the template public function assign($variable,$value=null) { $this->var[$variable]=$value; } public function display($templa

  • 需要使用php模板的朋友必看的很多个顶级PHP模板引擎比较分析

    Smarty Smarty的特点是将模板编译成PHP脚本,然后执行这些脚本.很快,非常灵活. Heyes Template Class 一个非常容易使用,但功能强大并且快速的模板引擎,它帮助你把页面布局和设计从代码中分离. FastTemplate 一个简单的变量插值模板类,它分析你的模板,把变量的值从HTML代码中分离处理. ShellPage 一个简单易用的类,可以让你的整个网站布局基于模板文件,修改模板就能改变整个站点. STP Simple Template Parser 一个简单.轻量

  • 自定义min版smarty模板引擎MinSmarty.class.php文件及用法

    本文实例讲述了自定义的min版smarty模板引擎MinSmarty.class.php文件.分享给大家供大家参考,具体如下: 一.smarty的优点 smarty是一个使用PHP写出来的模板引擎,是目前业界最著名的PHP模板引擎之一.它分离了逻辑代码和外在的内容,提供了一种易于管理和使用的方法,用来将原本与HTML代码混杂在一起PHP代码逻辑分离.简单的讲,目的就是要使PHP程序员同前端人员分离,使程序员改变程序的逻辑内容不会影响到前端人员的页面设计,前端人员重新修改页面不会影响到程序的程序逻

  • CodeIgniter使用phpcms模板引擎

    CodeIgniter很适合小站点应用开发,但是它自带的view功能可能会给不懂PHP的前端人员带来麻烦. 相比之下phpcms的view模板解析就强大多了,所以这里就把PHPCMS的模板解析功能剥离出来,加到PHPCMS上.首先在CodeIgniter libraries中 增加 template_cache.php 复制代码 代码如下: <?php if (!defined('BASEPATH')) exit('No direct script access allowed'); /** *

  • PHP实现简单的模板引擎功能示例

    本文实例讲述了PHP实现简单的模板引擎功能.分享给大家供大家参考,具体如下: php web开发中广泛采取mvc的设计模式,controller传递给view层的数据,必须通过模板引擎才能解析出来.实现一个简单的仅仅包含if,foreach标签,解析$foo变量的模板引擎. 编写template模板类和compiler编译类.代码如下: <?php namespace foo\base; use foo\base\Object; use foo\base\Compiler; /** * */ c

  • PHP中MVC模式的模板引擎开发经验分享

    使Web系统的开发与维护更加方便,从而有效的节省人力物力,受到了越来越多企业的青眯. 模板引擎是MVC模式建立过程的重要方法,开发者可以设计一套赋予含义的标签,通过技术解析处理有效的把数据逻辑处理从界面模板中提取出来,通过解读标签的含义把控制权提交给相应业务逻辑处理程序,从而获取到需要的数据,以模板设计的形式展现出来,使设计人员能把精力更多放在表现形式上.下面是我对模板引擎的认识与设计方法: 说的好听些叫模板引擎,实际就是解读模板数据的过程(个人观点^^).通过我对建站方面的思考认识,网站在展现

  • PHP的自定义模板引擎

    前面的话 在大多数的项目组中,开发一个Web程序都会出现这样的流程:计划文档提交之后,前端工程师制作了网站的外观模型,然后把它交给后端工程师,它们使用后端代码实现程序逻辑,同时使用外观模型做成基本架构,然后工程被返回到前端工程师继续完善.就这样工程可能在后端工程师和前端工程师之间来来回回好几次.由于后端工程师不干预任何相关HTML标签,同时也不需要前端代码和后端代码混合在一起.前端工程师只需要配置文件,动态区块和其他的界面部分,不必要去接触那些错综复杂的后端代码.因此,这时候有一个很好的模板支持

随机推荐