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 = '/\{\$([\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 (点击即可下载)

    学而时习之,不亦说乎?有朋自远方来,不亦乐乎?*\(^v^)/*
  • 相关阅读:
    jedis异常:Could not get a resource from the pool
    redis.clients.jedis.exceptions.JedisConnectionException: Could not get a resourc
    【redis】常见JedisConnectionException异常分析
    JAVA,字符串首字母转大写(高效率)
    Type handler was null on parameter mapping for property 'products'. It was either not specified and/or could not be found for the javaType / jdbcType combination specified
    java读取blob,clob转换为字符串
    mybatis对blob属性数据的处理
    mybatis读取oracle中blob
    jpa2.x的getOne()/findOne()/findById()的区别及使用
    IDEA如何导入导出出settings配置文件
  • 原文地址:https://www.cnblogs.com/isuhua/p/3019377.html
Copyright © 2011-2022 走看看