+ -
当前位置:首页 → 问答吧 → 简单的写了一个模板引擎

简单的写了一个模板引擎

时间:2010-06-29

来源:互联网

<?php
/**
* 默默基于Discuz的模板引擎开发的OOP类模板引擎,可支持模板缓存并生成hash的md5值。由hash值来判断模板是否被修改,假如被修改则重新生成缓存文件,假如没有被修改,则直接调用缓存文件.
* 版本:1.0.0.1 beta 测试版
*/
class mmtp{

        var $left_tags="{";
        var $right_tags="}";
        var $tp_suffix=".html";
        var $cache_suffix=".tpl";
        var $tp_dir="./";
        var $cache_dir="./";
        
        /**
         * 允许循环嵌套的次数,默认为5
         *
         * @var unknown_type
         */
        var $nest = 5;    
    /**
     * 模板路径
     *
     * @param unknown_type $tp_dir
     * @return mmtp
     */
        
        function __setdir($tp_dir){
                        if(file_exists($tp_dir)){
                                $this->tp_dir=$tp_dir;
                        }else{
                                $this->error("模板路径不存在");
                        }
        }
        
        /**
         * 设置缓存目录
         *
         * @param unknown_type $cache_dir
         */
        function __setcdir($cache_dir){
                                if(file_exists($cache_dir)){
                                $this->cache_dir=$cache_dir;
                        }else{
                                $this->error("缓存路径不存在");
                        }
        }

    /**
     * 输出错误信息
     *
     * @param unknown_type $msg
     */
  
        function error($msg){
                print "<div style=\"font-size:12px;color:red;\">".$msg."</div>";
        }
        
        /**
         * 解析模板
         *
         * @param unknown_type $file
         */
        
        function tp($file){
                $tp_path=$this->tp_dir.$file.$this->tp_suffix;
                $fp=fopen($tp_path,"rb");
                if(!$this->file_test($tp_path,"r") && !$this->match_hash($file)){
                        $template=$this->file_read($tp_path);
                        
                    $var_regexp = "((\\\$[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)(\[[a-zA-Z0-9_\-\.\"\'\[\]\$\x7f-\xff]+\])*)";
                    $const_regexp = "([a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*)";
                        $template = preg_replace("/([\n\r]+)\t+/s", "\\1", $template);
                        $template = preg_replace("/\<\!\-\-\{(.+?)\}\-\-\>/s", "{\\1}", $template);
                        $template = preg_replace("/\{lang\s+(.+?)\}/ies", "languagevar('\\1')", $template);
                        $template = str_replace("{LF}", "<?=\"\\n\"?>", $template);

                        $template = preg_replace("/\{(\\\$[a-zA-Z0-9_\[\]\'\"\$\.\x7f-\xff]+)\}/s", "<?=\\1?>", $template);
                        $template = preg_replace("/$var_regexp/es", "\$this->addquote('<?=\\1?>')", $template);
                        $template = preg_replace("/\<\?\=\<\?\=$var_regexp\?\>\?\>/es", "\$this->addquote('<?=\\1?>')", $template);

                        
                        $template = preg_replace("/[\n\r\t]*\{template\s+([a-z0-9_]+)\}[\n\r\t]*/is", "\n<? include('".$this->cache_dir."\\1".$this->cache_suffix."'); ?>\n", $template);
                        $template = preg_replace("/[\n\r\t]*\{template\s+(.+?)\}[\n\r\t]*/is", "\n<? include('".$this->cache_dir."\\1".$$this->cache_suffix."'); ?>\n", $template);
                        $template = preg_replace("/[\n\r\t]*\{eval\s+(.+?)\}[\n\r\t]*/ies", "\$this->stripvtags('\n<? \\1 ?>\n','')", $template);
                        $template = preg_replace("/[\n\r\t]*\{echo\s+(.+?)\}[\n\r\t]*/ies", "\$this->stripvtags('\n<? echo \\1; ?>\n','')", $template);
                        $template = preg_replace("/[\n\r\t]*\{elseif\s+(.+?)\}[\n\r\t]*/ies", "\$this->stripvtags('\n<? } elseif(\\1) { ?>\n','')", $template);
                        $template = preg_replace("/[\n\r\t]*\{else\}[\n\r\t]*/is", "\n<? } else { ?>\n", $template);

                        for($i = 0; $i < $this->nest; $i++) {
                        $template = preg_replace("/[\n\r\t]*\{loop\s+(\S+)\s+(\S+)\}[\n\r]*(.+?)[\n\r]*\{\/loop\}[\n\r\t]*/ies", "\$this->stripvtags('\n<? if(is_array(\\1)) { foreach(\\1 as \\2) { ?>','\n\\3\n<? } } ?>\n')", $template);
                        $template = preg_replace("/[\n\r\t]*\{loop\s+(\S+)\s+(\S+)\s+(\S+)\}[\n\r\t]*(.+?)[\n\r\t]*\{\/loop\}[\n\r\t]*/ies", "\$this->stripvtags('\n<? if(is_array(\\1)) { foreach(\\1 as \\2 => \\3) { ?>','\n\\4\n<? } } ?>\n')", $template);
                        $template = preg_replace("/[\n\r\t]*\{if\s+(.+?)\}[\n\r]*(.+?)[\n\r]*\{\/if\}[\n\r\t]*/ies", "\$this->stripvtags('\n<? if(\\1) { ?>','\n\\2\n<? } ?>\n')", $template);
                        }

                        $template = preg_replace("/\{$const_regexp\}/s", "<?=\\1?>", $template);
                        $template = preg_replace("/ \?\>[\n\r]*\<\? /s", " ", $template);
                        $hash=$this->file_hash($tp_path);
                        $head_hash="<!-- hash=".$hash." -->";
                        $foot_time="<!-- time=".(date("Y-m-d G:i:s"))." -->";
                        $this->file_write($this->cache_dir.$file.".tpl",$head_hash.$template.$foot_time);
                        
                        
                        
                }
        }
        
        
        /**
         * 检查文件是否存在并且有读取权限
         *
         * @param unknown_type $path
         */
        
        function file_test($path,$method){
                if(!file_exists($path) || !fopen($path,$method)){
                        $this->error("模板文件不存在,或没有操作权限");
                        return false;
                }
        }
        
        /**
         * 读取文件内容
         *
         * @param unknown_type $path
         * @return unknown
         */
        function file_read($path,$length=0){
                if(!$this->file_test($path,"r+")){
                $fp=@fopen($path,"r+");
                if($length==0){
                        $contents=@fread($fp,filesize($path));
                }else{
                        $contents=@fread($fp,$length);
                }
                fclose($fp);
                return $contents;
                }
        }
        
        
        /**
         * 写入文件内容
         *
         * @param unknown_type $path
         * @param unknown_type $puts
         */
        function file_write($path,$puts){
                
                if(!$this->file_test($path,"w+")){
                $fp=@fopen($path,"w+");
                @fwrite($fp,$puts);
                fclose($fp);
                }
                
        }
        
        
        /**
         * 计算文件的hash
         *
         * @param unknown_type $path
         * @return unknown
         */
        function file_hash($path){
                return md5_file($path);
        }
        
        
        /**
         * 对比模板文件与缓存文件的hash值
         *
         * @param unknown_type $file
         * @return unknown
         */
        function match_hash($file){
                $read_hash=$this->file_read($this->cache_dir.$file.$this->cache_suffix,46);
                
                $html_hash=$this->file_hash($this->tp_dir.$file.$this->tp_suffix);
                
                        if(preg_match("/".$html_hash."/i",$read_hash)){
                        return true;
                }
                
        }
        
        function addquote($var) {
        return str_replace("\\\"", "\"", preg_replace("/\[([a-zA-Z0-9_\-\.\x7f-\xff]+)\]/s", "['\\1']", $var));
        }
        
        function transamp($str) {
        $str = str_replace('&', '&', $str);
        $str = str_replace('&amp;', '&', $str);
        $str = str_replace('\"', '"', $str);
        return $str;
}

        function stripvtags($expr, $statement) {
        $expr = str_replace("\\\"", "\"", preg_replace("/\<\?\=(\\\$.+?)\?\>/s", "\\1", $expr));
        $statement = str_replace("\\\"", "\"", $statement);
        return $expr.$statement;
}
        
}


$tp=new mmtp();
$tp->__setdir("./");
$tp->__setcdir("./cache/");
$tp->tp("index1");
$_GET[it]=sdhkadajksdhajdhkajsdhjkasdjkasdhasjdhkjsadhk;
$name=2;
$head="欢迎使用MoMo模板引擎";
include("./cache/index1.tpl");
?>

作者: wu1jun   发布时间: 2010-06-29

discuz虽为PHP的旗舰级产品,但它的代码也不一定都是正确的。
大虾们,别再跟风了……

根据这个类提点意见:
1、单文件的判断用is_file比file_exists快N倍;
2、PHP5基本已是普及,用file_get_contents系列函数比用fopen来得更方便更效率;
3、用md5_file()与preg_match()来计算文件的hash是没必要的,用filemtime()就可轻易的比较出两个文件的区别;
4、这项是最要命的,请数下在这函数里用了多少次preg_replace(),难道不知道preg_replace()是可以用数组的吗?preg_replace(array(),array(),$template)一次完成;
5、str_replace()使用方法同上,也是可以用数组的,完全没必要一个个的写。

作者: free212   发布时间: 2010-06-29

不错

作者: cgw   发布时间: 2010-06-29

看不懂啊

作者: hyj多喝水   发布时间: 2010-06-29

1楼的说的不错

作者: anton   发布时间: 2010-06-30

路过看看

作者: weixiao---mt   发布时间: 2010-07-10

顶一下!牛人

作者: cyr11   发布时间: 2010-07-11

路过。。。

作者: ddissuper   发布时间: 2010-07-11

preg_replace 太多会不会降低程序执行速度啊..

作者: pksk.mfk   发布时间: 2010-08-29