PHP--关于模板的原理和解析

此内容用作笔记,以备日后查看,此内容为学习李炎恢课程而来,并非自己所创,如有问题请私信~

将PHP代码和静态HTML代码进行分离,使代码的可读性和维护性得到显著提高。

使用模板引擎:

    我们所说的模板是Web模板,是主要由HTML标记组成的语言来编写的页面,但也有如何表示包含动态生成内容的方式(解析标签)。模板引擎是一种软件库,允许我们从模板生成HTML代码,并指定要包含的动态内容。

  模板引擎的特点:

  1.鼓励分离:让更个系统的可读性和维护性得到提高。
  2.促进分工:使得程序员和美工去专心处理自己的设计。
  3.比PHP更容易解析:编译文件和缓存文件加载更快、占资源更少。
  4.增加安全性:可限制模板设计师进行不安全的操作的能力避免误删误访问等。

模板处理的流程图

  

 

创建模板:

  1、创建初始模板所需要的文件夹和文件。

  a) index.php主文件,用于编写业务逻辑。
  b) template.inc.php模板初始化文件,用于初始模版信息。
  c) templates目录存放所有的模板文件。
  d) templates_c目录存放所有编译文件。
  e) cache目录存放所有缓存文件。
  f) includes目录存放所有的类文件。
  g) config目录存放模板系统变量配置文件。

  

  以下是源码:

主文件 index.php  

复制代码
<?php
   //index.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_DIR', ROOT_PATH.'/cache/');
  //定义缓存状态
  define('IS_CACHE',true);
  //设置缓存状态开关
  IS_CACHE ? ob_start() : null;

  include ROOT_PATH.'/includes/Templates.class.php';

  $_name = '方块李';
    
    $array = array(1,2,3,4,5,6);
    $_tpl = new Templates();
    $_tpl->assign('name', $_name);
    $_tpl->assign('a', 5>4);
    $_tpl->assign('array', $array);
    //显示
    $_tpl->display('index.tpl');
?>
复制代码

模板文件 HTML

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<! DOCTYPE  html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
< html  xmlns="http://www.w3.org/1999/xhtml">
< head >
< meta  http-equiv="Content-Type" content="text/html; charset=UTF-8" />
< title > <!--{webname}--> </ title >
 
</ head >
< body >
{include "test.php"}
<!-- 这是HTML的注释 -->
{#}这是一条PHP的注释,在HTML页面里是不显示的,只会在生成的编译文件里显示{#}
我将被index.php导入
{$name}这个标签必须经过Parser.class.php这个解析类来解析它1
< br  />
这里的内容改变了,为什么?
< br  />
{if $a}
显示一号皮肤
{else}
显示二号皮肤
{/if}
< br  />
{foreach $array(key,value)}
{@key}....{@value} < br  />
{/foreach}
</ body >
</ html >

  

模板类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
      //Templates.class.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_DIR) ){
             exit ( 'ERROR:模板文件夹或者编译文件夹或者缓存文件夹没有创建!' );
         }
         //获取系统变量
         $_sxe  = simplexml_load_file(ROOT_PATH. '/config/profile.xml' );
         $_taglib  $_sxe ->xpath( '/root/taglib' );
         foreach ( $_taglib  as  $_tag ){
             $this ->_config[ "$_tag->name" ] =  $_tag ->value;
         }
     }
   
     
     //创建变量注入方法
     /**
      * assign()变量注入方法
      * @param  $_var 要注入的变量名,对应.tpl文件中的需要替换的变量
      * @param  $_values 要注入的变量值
      */
     public  function  assign( $_var , $_values ){
         if (isset( $_var ) && ! empty ( $_var )){
             $this ->_vars[ $_var ] =  $_values ;
             
         } else {
             exit ( 'ERROR:请设置变量名!' );
         }
         
     }
     
     
     //创建一个显示方法,用来显示编译后的文件
     public  function  display( $_file ){
         //设置模板文件的路径
         $_tplFile  = TPL_DIR. $_file ;
         //判断模板文件是否存在
         if (! file_exists ( $_tplFile )){
             exit ( 'ERROR:模板文件不存在' );
         }
         //设置编译文件名
         $_parFile   = TPL_C_DIR.md5( $_file ). $_file . '.php' ;
         //设置缓存文件名
         $_cacheFile  = CACHE_DIR.md5( $_file ). $_file . '.html' ;
         //判断缓存状态
         if (IS_CACHE){
             //判断缓存文件是否存在
             if ( file_exists ( $_cacheFile ) &&  file_exists ( $_parFile )){
                 //是否修改过编译文件或者模板文件
                 if ( filemtime ( $_cacheFile )>= filemtime ( $_parFile ) &&  filemtime ( $_parFile )> filemtime ( $_tplFile )){
                     echo  '以下是缓存文件内容' ;
                     echo  "<br />" ;
                     include  $_cacheFile ;
                     return ;
                 }
             }
         }
         //判断编译文件是否存在,模板文件是否修改过
         if (! file_exists ( $_parFile ) || ( filemtime ( $_parFile ) <  filemtime ( $_tplFile ))){
             
             //引入模板解析类
             require  ROOT_PATH. '/includes/Parser.class.php' ;
             //实例化对象,生成编译文件
             $_parser  new  Parser( $_tplFile ); //模板文件
             $_parser ->compile( $_parFile ); //编译后文件
             
         }
 
         //载入编译文件
         include  $_parFile ;
         if (IS_CACHE){
             //生成缓存文件
             file_put_contents ( $_cacheFile , ob_get_contents());
             //清除缓冲区
             ob_end_clean();
             //载入缓存文件
             include  $_cacheFile ;
         }
 
 
     }
}

解析类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
//Parser.class.php
     class  Parser {
         //获取模板内容
         private  $_tpl ;
         //构造方法,初始化模板
         public  function  __construct( $_tplFile ){
             //判断文件是否存在
             if (! $this ->_tpl =  file_get_contents ( $_tplFile )){
                 exit ( 'ERROR:读取模板出错!' );
             }
             
         }
         
         //解析普通变量
         private  function  parVar(){
             $_pattern  '/\{\$([\w]+)\}/' ;
             if  (preg_match( $_pattern , $this ->_tpl)) {
                 $this ->_tpl = preg_replace( $_pattern , "<?php echo \$this->_vars['$1'] ?>" , $this ->_tpl);
             }
         }
         //解析IF条件语句
         private  function  parIf(){
             //开头if模式
             $_patternIf  '/\{if\s+\$([\w]+)\}/' ;
             //结尾if模式
             $_patternEnd  '/\{\/if\}/' ;
             //else模式
             $_patternElse  '/\{else\}/' ;
             //判断if是否存在
             if (preg_match( $_patternIf $this ->_tpl)){
                 //判断是否有if结尾
                 if (preg_match( $_patternEnd $this ->_tpl)){
                     //替换开头IF
                     $this ->_tpl = preg_replace( $_patternIf "<?php if(\$this->_vars['$1']){ ?>" $this ->_tpl);
                     //替换结尾IF
                     $this ->_tpl = preg_replace( $_patternEnd "<?php } ?>" $this ->_tpl);
                     //判断是否有else
                     if (preg_match( $_patternElse $this ->_tpl)){
                         //替换else
                         $this ->_tpl = preg_replace( $_patternElse "<?php }else{ ?>" $this ->_tpl);
                     }
                 } else {
                     exit ( 'ERROR:语句没有关闭!' );
                 }
             }
         }
         //解析foreach
         private  function  parForeach(){
             $_patternForeach  '/\{foreach\s+\$(\w+)\((\w+),(\w+)\)\}/' ;
             $_patternEndForeach  '/\{\/foreach\}/' ;
             //foreach里的值
             $_patternVar  '/\{@(\w+)\}/' ;
             //判断是否存在
             if (preg_match( $_patternForeach $this ->_tpl)){
                 //判断结束标志
                 if (preg_match( $_patternEndForeach $this ->_tpl)){
                     //替换开头
                     $this ->_tpl = preg_replace( $_patternForeach "<?php foreach(\$this->_vars['$1'] as \$$2=>\$$3){?>" $this ->_tpl);
                     //替换结束
                     $this ->_tpl = preg_replace( $_patternEndForeach "<?php } ?>" $this ->_tpl);
                     //替换值
                     $this ->_tpl = preg_replace( $_patternVar "<?php echo \$$1?>" $this ->_tpl);
                 } else {
                     exit ( 'ERROR:Foreach语句没有关闭' );
                 }
             }
         }
         //解析include
         private  function  parInclude(){
             $_pattern  '/\{include\s+\"(.*)\"\}/' ;
             if (preg_match( $_pattern $this ->_tpl, $_file )){
                 //判断头文件是否存在
                 if (! file_exists ( $_file [1]) ||  empty ( $_file [1])){
                     exit ( 'ERROR:包含文件不存在!' );
                 }
                 //替换内容
                 $this ->_tpl = preg_replace( $_pattern "<?php include '$1';?>" $this ->_tpl);
             }
         }
         //解析系统变量
         private  function  configVar(){
             $_pattern  '/<!--\{(\w+)\}-->/' ;
             if (preg_match( $_pattern $this ->_tpl, $_file )){
                 $this ->_tpl = preg_replace( $_pattern , "<?php echo \$this->_config['$1'] ?>" $this ->_tpl);
                 
             }
         }
         
         //解析单行PHP注释
         private  function  parCommon(){
             $_pattern  '/\{#\}(.*)\{#\}/' ;
             if (preg_match( $_pattern $this ->_tpl)){
                 $this ->_tpl = preg_replace( $_pattern "<?php /*($1) */?>" $this ->_tpl);
             }
         }
         
         
         //生成编译文件
         public  function  compile( $_parFile ){
             //解析模板变量
             $this ->parVar();
             //解析IF
             $this ->parIf();
             //解析注释
             $this ->parCommon();
             //解析Foreach
             $this ->parForeach();
             //解析include
             $this ->parInclude();
             //解析系统变量
             $this ->configVar();
             //生成编译文件
             if (! file_put_contents ( $_parFile $this ->_tpl)){
                 exit ( 'ERROR:编译文件生成失败!' );
             }
         }
     }

  

总结:模板引擎的整个过程:

  1、当浏览器请求index.php文件时,实例化模板类对像 $_tpl = new Templates();

  2、当Templates实例化的时候,生成两个数组,一个用来存放模板变量,另一个存放系统变量,通过构造方法,判断文件夹是否存在,同时通过XML文件将系统变量数组初始化

  3、通过模板类Templates的注入方法,assign(),将对应模板index.tpl中变量的index.php的内容注入到模板类的私有变量,完成初始化

  4、模板类Templates类显示方法display() 通过实例化解析类Parser,将取到的注入变量通过解析类进行解析(即替换)

  5、解析(替换)后,将文件写入PHP、HTML混全文件

  6、通过Templates类的显示方法将文件输出:

     1、第一次执行显示方法时,将会把PHP、HTML混合文件,生成纯静态的缓存文件

     2、调用缓存文件,显示页面

     3、当浏览器再次调用显示方法时,首先根据各文件的最后修改时间,判断是否重新生成缓存文件或直接调用已存在的缓存文件

重点:

  1、通过正则表达式进行字符串的替换

  2、熟悉OOP

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值