写一个迷你版Smarty模板引擎,对认识模板引擎原理非常好(附代码)
前些时间在看创智博客韩顺平的Smarty模板引擎教程,再结合自己跟李炎恢第二季开发中CMS系统写的tpl模板引擎。今天就写一个迷你版的Smarty引擎,虽然说我并没有深入分析过Smarty的源码,但是对模板引擎的原理,还是有深刻的理解的。如果有什么还需要改进的地方,记得提出来。
一、什么是Smarty模板引擎:
Smarty是一个使用PHP写出来的模板引擎,是目前业界最著名的PHP模板引擎之一。它分离了逻辑代码和外在的内容,提供了一种易于管理和使用的方法,用来将原本与HTML代码混杂在一起PHP代码逻辑分离。简单的讲,目的就是要使PHP程序员同前端人员分离,使程序员改变程序的逻辑内容不会影响到前端人员的页面设计,前端人员重新修改页面不会影响到程序的程序逻辑,这在多人合作的项目中显的尤为重要。(来自百度百科)
自己的理解是:
第一,有利于把前端开发与后台开发工作分离,利于分工合作;
第二,其缓存机制,有利于加快网站的访问速度;
第三,模板标签还可以一次编写,到处调用,便利和简洁性好;
二、下面就一起开发迷你版模板引擎吧
(1)首先先把已经做好的模板引擎给大家看一看,先使用,再开发
① 迷你版Smarty模板引擎目录结构如下:
源代码里面有很详细的说明,请看下面
① 要开发一个模板引擎,最主要的有两个类,分别是模板引擎入口类和模板解析类。
A.首先创建MiniSmarty目录,然后新建一个文件名为MiniSmarty.class.php
其代码如下:

/**
* MiniSmarty模板引擎
* @link http://www.cnblogs.com/isuhua/
* @author 华仔_suhua <weibo.com/suhua123>
* @package MiniSmarty
* @version 0.0.0.1
*/
class MiniSmarty {
//模板文件
public $template_dir = 'templates';
//编译文件
public $compile_dir = 'templates_c';
//缓存文件
public $cache_dir = 'cache';
//模板变量
public $_tpl_var = array();
//是否开启缓存
public $caching = false; public function __construct() {
$this->checkDir();
} //检查目录是否建好
private function checkDir() {
if (!is_dir($this->template_dir)) {
exit('模板文件目录templates不存在!请手动创建');
}
if (!is_dir($this->compile_dir)) {
exit('编译文件目录templates_c不存在!请手工创建!');
}
if (!is_dir($this->cache_dir)) {
exit('缓存文件目录'.$this->cache_dir.'不存在!请手工创建!');
}
} //模板变量注入方法
public function assign($tpl_var, $var = null) {
if (isset($tpl_var) && !empty($tpl_var)) {
$this->_tpl_var[$tpl_var] = $var;
} else {
exit('模板变量名没有设置好');
}
} //文件编译
public function display($file) {
//模板文件
$tpl_file = $this->template_dir.'/'.$file;
if (!file_exists($tpl_file)) {
exit('ERROR:模板文件不存在!');
}
//编译文件
$parse_file = $this->compile_dir.'/'.md5($file).$file.'.php'; //只有当编译文件不存在或者是模板文件被修改过了
//才重新编译文件
if (!file_exists($parse_file) || filemtime($parse_file) < filemtime($tpl_file)) {
include 'smarty_compile.class.php';
$compile = new Smarty_Compile($tpl_file);
$compile->parse($parse_file);
} //开启了缓存才加载缓存文件,否则直接加载编译文件
if ($this->caching) {
//缓存文件
$cache_file = $this->cache_dir.'/'.md5($file).$file.'.html';
//只有当缓存文件不存在,或者编译文件已被修改过
//重新生成缓存文件
if (!file_exists($cache_file) || filemtime($cache_file) < filemtime($parse_file)) {
//引入缓存文件
include $parse_file;
//缓存内容
$content = ob_get_clean();
//生成缓存文件
if (!file_put_contents($cache_file, $content)) {
exit('缓存文件生成出错!');
}
}
//载入缓存文件
include $cache_file;
} else {
//载入编译文件
include $parse_file;
}
}
}

B.然后再新建一个MiniSmarty模板引擎解析器类文件:MiniSmarty_Compile.class.php
其代码如下:

<?php
/**
* MiniSmarty模板引擎
* @link http://www.cnblogs.com/isuhua/
* @author 华仔_suhua <weibo.com/suhua123>
* @package MiniSmarty
* @version 0.0.0.1
*/
class MiniSmarty_Compile {
//模板内容
private $content = ''; //构造函数
public function __construct($tpl_file) {
$this->content = file_get_contents($tpl_file);
} //解析普通变量,如把{$name}解析成$this->_tpl_var['name']
public function parseVar() {
$pattern = '/\{\$([\w\d]+)\}/';
if (preg_match($pattern, $this->content)) {
$this->content = preg_replace($pattern, '<?php echo \$this->_tpl_var["$1"]?>', $this->content);
}
} //这里可以自定义其他解析器... //模板编译
public function parse($parse_file) {
//调用普通变量解析器
$this->parseVar();
//这里可以调用其他解析器... //编译完成后,生成编译文件
if (!file_put_contents($parse_file, $this->content)) {
exit('编译文件生成出错!');
}
}
}
?>

C.最后,还必须新建几个目录,分别是模板文件目录templates、编译文件目录 template_c、缓存文件目录cache。
如果你(ˇˍˇ) 想~一次性成功,就必须创建这几个目录,缺一不可。否则就会报错,然后要求你手动创建。
D.来试试看吧,编写demo.php,测试一下自定义的迷你版MiniSmarty模板引擎吧!
demo.php代码如下:

//引入模板引擎
require 'MiniSmarty.class.php';
//实例化模板类
$minismarty = new MiniSmarty();
//缓存开关
$minismarty->caching = true; //定义变量
$webname = '迷你版Smarty测试';
$author = 'suhua';
$title = '这是一个测试标题';
$content = '这是一段测试内容'; //注入变量
$minismarty->assign('webname', $webname);
$minismarty->assign('author', $author);
$minismarty->assign('title', $title);
$minismarty->assign('content', $content); //启动编译模板文件
$minismarty->display('demo.tpl');

测试前,请先看一下template、template_c 以及cache目录各自的状态,请看下图:
E:打开浏览器,输入http://localhost/MiniSmarty/demo.php,即可看到一下效果:
测试后,请再次看一下各目录的状态:
在template_c目录和cache目录下都分别多了一个xxxx.tpl.php和xxx.tpl.html文件,为什么呢?
答:这就是模板引擎非常重要的一个作用,编译文件并生成静态文件。对于如何实现的,这里不做解析,源码已经给出,看看就懂。
---->至此表示自己开发的一个迷你版Smarty模板引擎成功!*\(^v^)/*
再次测试一下缓存功能是否生效了,首先修改demo.php中的代码,改动如下:
把 $author = 'suhua'; 修改为 $author = 'xiwang';
改动过后,记得保存,然后再次刷新页面,看出现什么状况了?
结果是:没有任何变化!这就正常了否则缓存功能没有实现。
???为什么没有任何变化呢
答:原因是我们在demo.php中开启了缓存功能
//缓存开关
$minismarty->caching = true;
请看代码。下面这段代码是MiniSmarty.class.php里面的,下面就是根据你是否开启缓存,决定是加载缓存文件还是编译文件。因为这里开启了,所以会直接加载缓存文件,所以就算你修改了原来的模板,依然没变化。

//开启了缓存才加载缓存文件,否则直接加载编译文件
if ($this->caching) {
//缓存文件
$cache_file = $this->cache_dir.'/'.md5($file).$file.'.html';
//只有当缓存文件不存在,或者编译文件已被修改过
//重新生成缓存文件
if (!file_exists($cache_file) || filemtime($cache_file) < filemtime($parse_file)) {
//引入缓存文件
include $parse_file;
//缓存内容
$content = ob_get_clean();
//生成缓存文件
if (!file_put_contents($cache_file, $content)) {
exit('缓存文件生成出错!');
}
}
//载入缓存文件
include $cache_file;
} else {
//载入编译文件
include $parse_file;
}

如果我在demo.php中把缓存功能关了呢,结果会如何?
即改动如下:
//缓存开关
$minismarty->caching = false; //关闭缓存功能
此时,当你再次刷新页面的时候,你会看到如下效果:
此时,作者一栏改变了,这说明了模板引擎此时并没有去加载缓存文件,而是直接加载了编译文件。所以会出现该效果。上面的代码也说明了这一点。
其他细节在源码中都有较详细的注释,在这里就不多说了,说一下其原理。
★ MiniSmarty模板引擎原理:(非常重要)
其原理也比较简单
① 首先模板引擎会加载模板文件templates/demo.tpl,然后调用模板编译类对其进行编译解析(说白了就是变量替换或者标签替换),编译后就会生成编译文件xxxx.tpl.php;
② 然后判断缓存是否开启,来决定是否生成缓存文件。其生成过程是:直接把xxx.tpl.php编译文件加载进来,然后再从缓冲区取出所有内容,清空缓冲区,把内容写入到缓存文件中xxx.tpl.html文件。
③ 模板文件demo.tpl是一个同时具有html和引擎标签的复合文件,编译文件xxx.tpl.php是把引擎标签替换成php代码,是具有php和html标签的复合文件,缓存文件xxx.tpl.html文件就是一个纯html的静态文件;
至此,迷你版MiniSmarty模板引擎开发完成!
其中,如果还有其他不好的地方,希望各位指出!谢谢。
最后附上:MiniSmarty源码.rar (点击即可下载)
写一个迷你版Smarty模板引擎,对认识模板引擎原理非常好(附代码)的更多相关文章
- 迷你版 smarty --模板引擎和解析
http://blog.ipodmp.com/archives/php-write-a-mini-smarty-template-engine/ 迷你版Smarty模板引擎目录结构如下: ① 要开发一 ...
- 一个用 C 语言写的迷你版 2048 游戏,仅仅有 500个字符
Jay Chan 用 C 语言写的一个迷你版 2048 游戏,仅仅有 487 个字符. 来围观吧 M[16],X=16,W,k;main(){T(system("stty cbreak&qu ...
- Koa源码解析,带你实现一个迷你版的Koa
前言 本文是我在阅读 Koa 源码后,并实现迷你版 Koa 的过程.如果你使用过 Koa 但不知道内部的原理,我想这篇文章应该能够帮助到你,实现一个迷你版的 Koa 不会很难. 本文会循序渐进的解析内 ...
- ASP.NET Core管道深度剖析(2):创建一个“迷你版”的管道来模拟真实管道请求处理流程
从<ASP.NET Core管道深度剖析(1):采用管道处理HTTP请求>我们知道ASP.NET Core请求处理管道由一个服务器和一组有序的中间件组成,所以从总体设计来讲是非常简单的,但 ...
- 动手写一个简单版的谷歌TPU-矩阵乘法和卷积
谷歌TPU是一个设计良好的矩阵计算加速单元,可以很好的加速神经网络的计算.本系列文章将利用公开的TPU V1相关资料,对其进行一定的简化.推测和修改,来实际编写一个简单版本的谷歌TPU.计划实现到行为 ...
- 直播的本质(创业者应该要从商业模式的右边开始思考,你为用户创造了什么价值?找客户并不难,但要想办法让客户不离不弃;PC端功能的丰富很重要,因为手机版通常只是一个迷你版)
我想稍微给直播这件事浇点冷水. 的确,直播现在越来越火,YouTube凭着良好的基础建设平台前段时间也做起了直播,Facebook Live最近也加入了变脸.预定直播时间和双人录制的功能,更不用说国内 ...
- 动手写一个简单版的谷歌TPU-指令集
系列目录 谷歌TPU概述和简化 基本单元-矩阵乘法阵列 基本单元-归一化和池化(待发布) TPU中的指令集 SimpleTPU实例: (计划中) 拓展 TPU的边界(规划中) 重新审视深度神经网络中的 ...
- 手写一个简版 asp.net core
手写一个简版 asp.net core Intro 之前看到过蒋金楠老师的一篇 200 行代码带你了解 asp.net core 框架,最近参考蒋老师和 Edison 的文章和代码,结合自己对 asp ...
- 来,我们手写一个简易版的mock.js吧(模拟fetch && Ajax请求)
预期的mock的使用方式 首先我们从使用的角度出发,思考编码过程 M1. 通过配置文件配置url和response M2. 自动检测环境为开发环境时启动Mock.js M3. mock代码能直接覆盖g ...
随机推荐
- thinkphp查询
public function index(){ $result = M('content')->select() $this->assig('result',$result); $thi ...
- js无间隙滚动
代码一: ; //设置文字滚动速度 dome2.innerHTML=dome1.innerHTML //复制dome1为dome2 function Marquee(){ ) //当滚动至dome1与 ...
- rz和sz上传下载文件工具lrzsz
######################### rz和sz上传下载文件工具lrzsz ####################################################### ...
- OC-SEL
SEL SEL对应方法的地址 _cmd代表当前方法 1. 方法的存储位置 每个类的方法列表都存储在类对象中 每个方法都有一个与之对应的SEL类型的对象 根据一个SEL对象就可以找到方法的地址,进而调 ...
- Flex调用java webservice
<?xml version="1.0" encoding="utf-8"?> <s:Application xmlns:fx="ht ...
- JS禁止WEB页面鼠标事件大全
<!--禁止鼠标右键代码-->:<noscript><ifra:<scriptlanguage=javas:<!--:if(window.Event):doc ...
- 通过google chrome操作JavaScript中Console
紧接着有关上一个文章的!function................. 前端开发人员一定会用到你的开发者工具中的Console控制台.通常Console用于调试程序,日志输出,打断点等功能.比如我 ...
- 【PHP面向对象(OOP)编程入门教程】18.__call()处理调用错误
在程序开发中,如果在使用对象调用对象内部方法时候,调用的这个方法不存在那么程序就会出错,然后程序退出不能继续执行.那么可不可以在程序调用对象内部 不存在的方法时,提示我们调用的方法及使用的参数不存在, ...
- PHP get_class 返回对象的类名
get_class (PHP 4, PHP 5) get_class — 返回对象的类名 说明 string get_class ([ object $obj ] ) 返回对象实例 obj 所属类的名 ...
- 如何打开xip格式的xcode安装包
解决方法如下: 1.保证存储空间 20G 2.去除解压验证 xattr -d com.apple.quarantine Xcode_8_beta.xip 3.双击解压 详见: 从官网下载的 xcode ...