zoukankan      html  css  js  c++  java
  • 写一个迷你版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 = '/{$([wd]+)}/';
            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 (点击即可下载)

  • 相关阅读:
    2021NUAA暑假集训 Day3 题解
    2021NUAA暑假集训 Day2 题解
    2021NUAA暑期模拟赛部分题解
    CodeForces 1038D Slime
    UVA 11149 Power of Matrix
    UVA 10655 Contemplation! Algebra
    UVA 10689 Yet another Number Sequence
    HDU 4549 M斐波那契数列
    HDU 4990 Reading comprehension
    CodeForces 450B Jzzhu and Sequences
  • 原文地址:https://www.cnblogs.com/zsw-1993/p/4879186.html
Copyright © 2011-2022 走看看