毛毛虫教你写一个属于自己的模板引擎(更新完毕)

#phpchina首发#

Smarty一直被人视为是多余的东西,我觉得认为Smarty多余的人才是多余的....不说这些了。今天我就教大家写个模板引擎,让大家都可以写一个属于自己的模板引擎,而且看完这篇文章之后,你对Smarty的认识会更进一步的。我的模板引擎名叫Stupid("傻瓜"的意思),我不喜欢太聪明的东西!
Stupid模板引擎是由3个文件组成,他们分别是:stupid.class.php,stupid_parser.class.php,stupid_debugger.class.php。
Stupid.class.php的任务是设置变量,模板路径,和显示等功能,而stupid_parser.class.php就是编译模板文件的,stupid_debugger.class.php是用来调试用的。


好了,我们现在就先编写stupid.class.php吧。
1.新建一个PHP文件名为:stupid.class.php。
我们的类叫Stupid,我们先设计一下成员变量吧。
成员变量有:$_tpl_vars, $_tpl_file, $_parser, $_debugger;
$_tpl_vars: 用来保存模板变量的;
$_tpl_file: 用来保存模板文件名的;
$_parser: 保存StupidParser对象的,就是编译对象;
$_debugger: 保存StupidDebug对象的,就是调试对象;

下面定义了两个常量,用来存放模板文件夹和编译文件夹的:
define('TPL_DIR', './templates/');
define('TPL_C_DIR', './templates_c/');

开始编码了>>>

<?php
define('TPL_DIR', './templates/');
define('TPL_C_DIR', './templates_c/');

class Stupid {
        private $_tpl_vars;
        private $_tpl_file;
        private $_parser;
        private $_debugger;
}
?>


开始写个构造器吧>>>

public function Stupid() {
  if(!is_dir(TPL_DIR) || !is_dir(TPL_C_DIR)) {
   exit('错误:请正确设置模板文件夹和编译文件夹');
  }
}

在构造器中,我们判断了模板路径和编译路径是否设置正确.

设计我们的方法
我们这个类中主要有以下方法:
assign(), set_tpl_dir(), set_parsed_dir(), display(), debug().
assign()方法:
assign()的用处是设置模板变量.代码如下>>>
[php]
public function assign($var, $value) {
if(isset($var) && trim($var) != '') {
                $this->_tpl_vars[$var] = $value;
                return true;
        } else {
                exit('错误:请设置变量名');
        }
}
[/php]

我们先判断用户是否设置了变量名,用isset($var) && trim($var) != ''来判断, trim($var) != ''是防止用户以空格来设置变量名.如果设置变量正确,我们就将他保存到成员变量_tpl_vars中.

display()方法
display()方法是Stupid类中最重要的方法,他是用来显示和检测模板是否更新了,更新了就再编译,没有更新就用原来编译之后的文件.

代码如下>>>

public function display($tpl_file) {
  $template_file = TPL_DIR.$tpl_file;
  if(!file_exists($template_file)) {
   exit('错误:模板文件不存在');
  }
  
  $parsed_file = TPL_C_DIR.md5($tpl_file).'.php';
  if(!file_exists($parsed_file) || filemtime($parsed_file) < filemtime($template_file)) {
   require_once './stupid_parser.class.php';
   $this->_parser = new StupidParser();
   $this->_parser->compile($tpl_file);
  }
  include $parsed_file;
}

这个方法是根据!file_exists($parsed_file)||filemtime($parsed_file)< filemtime($template_file)这条语句来判断是否编译过和模板文件是否更新过, 没有编译过和更新过模板文件都要重新编译.我们就要引入stupid_parser.class.php,并创建StupidParser对象,对模板文件进行编译.编译完,我们就引入编译之后的文件.这个编译之后的模板文件就是一个普通的PHP文件.

debug()方法
Debugg()方法就比较简单,就是引入stupid_debugger.class.php文件,创建StupidDebuger对象,调用StupidDebuger的start方法进行调试.

代码如下>>>

public function debug ($tpl_file) {
        if (include_once("stupid_debugger.class.php")) {
                $this->_debugger = new StupidDebugger($tpl_file);
                $this->_debugger->start();
        } else {
                exit( '错误:Debuger类文件不存在');
        }
}

至此,我们的Stupid类就写完了!下次我要介绍StupidParser类的编写.请继续支持.大家有什么意见或者建议可以提出!

show show全相:
[php]
<?php
define('TPL_DIR', './templates/');
define('TPL_C_DIR', './templates_c/');
class Stupid {
private $_tpl_vars;
private $_tpl_file;
private $_parser;
private $_debug;

public function Stupid() {
  if(!is_dir(TPL_DIR) || !is_dir(TPL_C_DIR)) {
   exit('错误:请正确设置模板文件夹和编译文件夹');
  }
}

public function assign($var, $value) {
  if(isset($var) && trim($var) != '') {
   $this->_tpl_vars[$var] = $value;
   return true;
  } else {
   exit('错误:请设置变量名');
  }
}

public function display($tpl_file) {
  $template_file = TPL_DIR.$tpl_file;
  if(!file_exists($template_file)) {
   exit('错误:模板文件不存在');
  }
  
  $parsed_file = TPL_C_DIR.md5($tpl_file).'.php';
  if(!file_exists($parsed_file) || filemtime($parsed_file) < filemtime($template_file)) {
   require_once './stupid_parser.class.php';
   $this->_parser = new StupidParser();
   $this->_parser->compile($tpl_file);
  }
  include $parsed_file;
}

function debug($tpl_file) {
  if (include_once("stupid_debugger.class.php")) {
   $this->_debugger = new StupidDebugger($tpl_file);
   $this->_debugger->start();
  } else {
   exit( '错误:Debuger类文件不存在');
  }
}
}
?>
[/php]

作者: liexusong   发布时间: 2008-11-30

跟毛毛虫学写一个属于自己的淫荡的模板引擎

作者: liexusong   发布时间: 2008-11-30

关注中..............

作者: TankMe   发布时间: 2008-11-30

关注中..............

作者: qxhy123   发布时间: 2008-11-30

多余的人路过,话说MVC做好的话,视图HTML PHP 分离实在是没多大意义

作者: wclssdn   发布时间: 2008-12-08

期待中·············

作者: 1oki   发布时间: 2008-12-08

期待...............

作者: keailyf   发布时间: 2008-12-08

广告位出租

作者: 张晨辉   发布时间: 2008-12-08

作者: wzj5   发布时间: 2008-12-08

非常期待。。。

作者: zfphp   发布时间: 2008-12-08

很快推出!大约这个星期之内会发布完成!请注意!

作者: 只喝可乐的猫   发布时间: 2008-12-08

一直都想写个自己的模板,期待你的详细介绍。。。。。。。。

作者: akas628   发布时间: 2008-12-08

期待...............

作者: liexusong   发布时间: 2008-12-08

期待LZ的大作

占位学习

作者: fly1983   发布时间: 2008-12-08

编译那个咱咋编译呢 ?正则?

作者: ★xxXxx★   发布时间: 2008-12-09

好  不错不错  得学习学习

作者: shanji   发布时间: 2008-12-09

期待LZ,过了一周了!

作者: volew   发布时间: 2008-12-09

跟毛毛虫学写一个属于自己的淫荡的模板引擎

作者: dinenghou   发布时间: 2008-12-09

更新了,请大家支持!!

作者: Deman   发布时间: 2008-12-09

不知道是否可以申精呢???

作者: 小鱼哥哥   发布时间: 2008-12-09

没有人支持!失望中................

作者: liexusong   发布时间: 2008-12-10

毛毛 你准备怎么编译这个文件捏~

作者: liexusong   发布时间: 2008-12-10

厉害,我还是先学smarty吧

作者: liexusong   发布时间: 2008-12-10

菜鸟来学习

作者: volew   发布时间: 2008-12-10

dingdingding

作者: sinopf   发布时间: 2008-12-10

收藏

作者: frode   发布时间: 2008-12-10

顶一个。。。争取早日整一个自己的framework出来。。。。

作者: COOKIETEST   发布时间: 2008-12-15

快更新快更新

作者: lanye   发布时间: 2008-12-15

没下文了?

作者: kakashilw   发布时间: 2008-12-16

写的很不错的呀

作者: COOKIETEST   发布时间: 2008-12-16

很牛很强大...

作者: jackygz   发布时间: 2008-12-22

期待更新!

作者: liangpz521   发布时间: 2008-12-22

kuai gengxina

作者: csyrpeng   发布时间: 2008-12-22

速度更新

作者: dirac   发布时间: 2008-12-22

这个星期之内会更新!谢谢支持!

作者: COOKIETEST   发布时间: 2008-12-22

好东西~~ 正好有个问题

作者: COOKIETEST   发布时间: 2008-12-22

最好也加个fetch方法,把display方法和fetch方法分开

作者: liexusong   发布时间: 2008-12-22

关注中..............

作者: wolf432   发布时间: 2008-12-22

更新完毕!谢谢大家支持!

作者: COOKIETEST   发布时间: 2008-12-23

没人支持??失望ing......

作者: delinking   发布时间: 2008-12-23

作者: liexusong   发布时间: 2008-12-24

下载看看

作者: liexusong   发布时间: 2008-12-24

好好研究  呵呵

作者: phpzxh   发布时间: 2008-12-24

多谢支持!还有以后我会写个关于smarty内核的教程!!方便大家学习smarty

作者: 阿米   发布时间: 2008-12-24

顶,学习ing

作者: okjoyel   发布时间: 2008-12-24

问一个弱弱的问题,为什么要两个斜杠才能匹配美元符号,一个斜杠不能匹配吗?
\\$和\$的区别是什么啊

作者: liexusong   发布时间: 2008-12-24

不能一个反斜杠的,因为第一个是用来转义PHP中的$,就是把$转成普通的字符,然后第二个反斜杠是用来正则表达式用的!!

作者: sinan62   发布时间: 2008-12-24

原帖由 liexusong 于 2008-12-25 15:56 发表
不能一个反斜杠的,因为第一个是用来转义PHP中的$,就是把$转成普通的字符,然后第二个反斜杠是用来正则表达式用的!!
恍然大悟!

作者: tetang1230   发布时间: 2008-12-25

咋个调用呢?

作者: liexusong   发布时间: 2008-12-25

原帖由 huangqyun 于 2008-12-27 00:12 发表
咋个调用呢?
哦!原来有点错误!对不起!!现在改过了!调用:

require_once 'stupid.class.php';
$s = new Stupid();
$s->debug('index.tpl');


模版

<html>
<head></head>
<body>
<h2>我的模板引擎</h2>
<p>My name is : {$myname}</p>
{$array->foreach(key,value)}
  No:{@value}<br/>
{/foreach}
{if $myname == 'Tony'} Yes , My name is Tony {/if}
{#}echo hello world{#}
{include ""}
</body>
</html>


作者: dirac   发布时间: 2008-12-26

发现个新问题,你用的<?php if ():   endif> 这是啥版本用到的语句,好像很早了吧。。。。

作者: huangqyun   发布时间: 2008-12-27

没错!是很早,不过到现在也支持这种用法的!

作者: liexusong   发布时间: 2008-12-27

难怪,记得从php3.0就开始有这种写法,现在都不流行了....哈,楼主也该适应一下时代潮流...

作者: huangqyun   发布时间: 2008-12-27

哈哈!不是潮流的问题~那种写法比较有层次感!

作者: liexusong   发布时间: 2008-12-27

即然还在,在问个问题,我看你在stupid_parser.class.php 文件中有个 $this->_tpl_vars['$1'] 的写法,我想问一下其中的'$1'是啥意思。

作者: huangqyun   发布时间: 2008-12-27

不错的说

作者: liexusong   发布时间: 2008-12-27

老大,求解呀,,在不!!!!!!!!!!!!!

作者: huangqyun   发布时间: 2008-12-27

原帖由 huangqyun 于 2008-12-27 01:43 发表
即然还在,在问个问题,我看你在stupid_parser.class.php 文件中有个 $this->_tpl_vars['$1'] 的写法,我想问一下其中的'$1'是啥意思。
就是第一个括号匹配的东西~

作者: xudongding   发布时间: 2008-12-27

支持楼主,要是代码里的注释写标准一点就更好了。

作者: huangqyun   发布时间: 2008-12-27

哈哈,我顶你个肺啊,顶顶顶,等了很久了

作者: liexusong   发布时间: 2008-12-27

多顶记下

作者: phpzxh   发布时间: 2008-12-28

路过,不错!

作者: COOKIETEST   发布时间: 2008-12-28

mark

作者: COOKIETEST   发布时间: 2008-12-28

MVC这个不单单是在模板上吧
我希望能够继续说说MVC调用数据库 方面的内容。

作者: davidachou   发布时间: 2008-12-28

谢谢,学习了

作者: go_tit   发布时间: 2008-12-28

受益匪浅。。。。
感谢ing...

作者: 李惟   发布时间: 2008-12-29

看不懂

作者: cqc1008   发布时间: 2008-12-31

mark一下

作者: libingcun   发布时间: 2009-01-02

多好的帖子啊
收藏!

作者: apgbb   发布时间: 2009-01-04

顶。。。。。。。。。。。。。。。。。。。。

作者: netbuddy   发布时间: 2009-01-07

[php]1.匹配变量的模式:{$var_name}2.匹配条件的模式:{if condition}.....................{/if}3.匹配注释的模式:{#}.......................................{#}4.匹配包含文件的模式:{include "file_name"}5.匹配foreach的模式(循环数组):{$array_name->foreach(key, value)}....................{/foreach}6.foreach中的变量表示:{@key} {@value}[/php]
这些能给写个使用的样例吗?我是新手,还不知道如何下手呢。

作者: konakona   发布时间: 2009-01-07

楼主很好很强大!太牛了,服了你了!

作者: lxydyx   发布时间: 2009-01-07

留个记号,有空来琢磨下

作者: phpstar   发布时间: 2009-01-28

靠,收藏了再说吧。收藏了当私货用

作者: lsx220   发布时间: 2009-01-29

好文,要学习!

作者: 古嗣小井   发布时间: 2009-01-30

很好

作者: 书君   发布时间: 2009-01-31

学习

作者: kingboer   发布时间: 2009-02-01

需要分页的时候怎么弄呢

作者: E蜗牛   发布时间: 2009-02-01

学习了,虽然不是很懂:

作者: ginux   发布时间: 2009-02-06

等着你呢。

作者: strongability   发布时间: 2009-02-15

private function _parse_include() {
        if(preg_match("/\{\s*include \"([^}]*)\"\s*\}/", $this->template, $file)) {
                if(trim($file[1]) == '') exit('错误:必须指定包含的文件');
                if(!file_exists(trim($file[1]))) exit('错误:文件不存在');


这个只检查一个的include文件是否存在.

作者: situlh   发布时间: 2009-02-17

2个foreach要怎么办哦?

{$arr->foreach(k, v)}
        {$v->foreach(key, value)}
                {@key}- {@value}
        {/foreach}
{/foreach}

作者: wanchun0222   发布时间: 2009-02-17

说真的,我只是介绍思想,而真正的实现要靠自己去努力了!!有不明白的可以与我讨论的,我很欢迎的!

作者: appz   发布时间: 2009-02-24

谢谢毛毛虫

作者: appz   发布时间: 2009-02-24

作者: liexusong   发布时间: 2009-02-24

做个记号。以后研究

作者: 站长刘   发布时间: 2009-02-25

学习学习

作者: liuxingyuyuni   发布时间: 2009-02-25

学习了。。。。。。。。

作者: xu569874   发布时间: 2009-02-25

先收藏~~回来学习学习~·

作者: bingbin1321   发布时间: 2009-02-25

楼主真强,学习了

作者: passter521   发布时间: 2009-03-05

收藏

作者: piaomiao163   发布时间: 2009-03-05

楼主厉害。
讲得很清楚。

作者: wxqaz   发布时间: 2009-03-11

不错好文章啊

作者: highjade   发布时间: 2009-04-06

毛毛虫太強了

作者: PHPShinelake   发布时间: 2009-04-22

好厉害啊,学习了

作者: dlcs286   发布时间: 2009-05-13

学习了......

作者: cvxcv   发布时间: 2009-05-13

lz写法好规范,真强~

作者: slg1984   发布时间: 2009-05-13

Thanks, 一直在找相关的东西。就是在编译那块过不去。

作者: luyinhu   发布时间: 2009-05-16

学习学习!!很受用

作者: FreeLiver   发布时间: 2009-05-16

做个标记

作者: fybird   发布时间: 2009-05-16

多余的人路过,话说MVC做好的话,视图HTML PHP 分离实在是没多大意义

作者: blackgood   发布时间: 2009-05-16



高手啊!你写的差不多我都能看懂,可是要我自己写,就写不出来。

这个就是菜鸟和高手之间的区别吧

作者: 哈出出   发布时间: 2009-05-18

跟毛毛学习

作者: qq88316793   发布时间: 2009-05-18

先收着...慢慢欣赏..

作者: mqh21364   发布时间: 2009-05-19

学习中^^^

作者: abc20053608   发布时间: 2009-06-17

谢了。

作者: chengwu555   发布时间: 2009-06-18

这些好东西,我怎么最近才发现呢?谢谢

作者: lc0633   发布时间: 2009-06-22

学学。

作者: qianzhengwei   发布时间: 2009-06-27

额....
我写的模板类不用正则,使用substr
嘿嘿,等把面向过程学好再学OOP

作者: daimadaquan   发布时间: 2009-06-27

跟毛毛虫虫学写一个属于自己的模板引擎
TankMe 发表于 2008-11-30 16:48

作者: yzhxiang   发布时间: 2009-06-27

占位学习中...

作者: kilobug   发布时间: 2009-06-28

好厉害啊

作者: 寒心   发布时间: 2009-07-22

即然有smrty干嘛要在换新的呢~ 成熟吗~
好用吗` 优化呢`
模板引擎说白了就是正则

作者: googlere   发布时间: 2009-07-27

模板引擎说白了就是正则

作者: linjize123   发布时间: 2009-07-27

呵呵,今天才看到,感觉不错,自己一直在用DISCUZ上抠下来的。

作者: fly_yang   发布时间: 2009-07-27

感觉不错

作者: wdvill   发布时间: 2009-08-10

..这个一定要学哈 。。。

作者: shinian315   发布时间: 2009-10-23

我现在还学模板分离的,只是有概念而已,完全是 .Net 的三层概念,估计差不是很多。

作者: wade2006   发布时间: 2009-10-24

让我 一次看个够0-0

作者: bing19880122   发布时间: 2009-10-24

可惜我不能加分

作者: 云端o枫o0   发布时间: 2009-10-26

不错不错,支持下

作者: cocoglp   发布时间: 2009-10-30

额。。路过看一下~

作者: 落寞三少   发布时间: 2009-11-23

谢谢LZ的分享

作者: poptang   发布时间: 2009-11-23

学习,哈哈

作者: zhoushj   发布时间: 2009-11-23

留个脚印 以后有时间再来看看
LZ辛苦了

作者: ainiaa   发布时间: 2009-11-24

留个记号,有空来琢磨下
跟着楼猪思想走

作者: 121928917   发布时间: 2009-12-02

关注中

作者: ainiaa   发布时间: 2009-12-04

有疏漏哦,条件中写的变量无法编译。
如if($title){},assgin过来的title,无法在if语句的括号中编译出来

作者: q60605   发布时间: 2009-12-08

记下了。等有时间试验下

作者: alice147   发布时间: 2009-12-14