仿制smarty模板

仿制smarty的模板技术,写了一个自己的mySmarty,供大家参考,和玩转

这是一个仿制的smarty模板
可以给简单变量以及数组变量赋值
在模板中可以使用foreach循环以及if条件语句


demo.php

caching = true;
    
    //定义变量
    $webname = 'my Smarty test';
    $message = array(
        'title'=>'this is title',
        'content',
        'userMessage'=>array(
            array('name'=>'this is johnny','gender'=>1),
            array('name'=>'this is lei','gender'=>1),
            array('name'=>'this is nicolas','gender'=>1),
            array('name'=>'this is ada','gender'=>0),
        ),
        'bookMessage'=> array(
            array('name'=>'this is johnny','id'=>1),
            array('name'=>'this is lei','id'=>2),
            array('name'=>'this is nicolas','id'=>3),
            array('name'=>'this is ada','id'=>4),
        ),
        array(
            'friendMessage'=>array(
                array('name','id'),
                array('johnny',1),
                array('nicolas',2),
                array('leiyuqing2222222222222',3),
            ),
        ),
        
    );
    
    $message1 = array(
        'userMessage'=>array(
            array('name'=>'this is johnny','gender'=>1),
            array('name'=>'this is lei','gender'=>1),
            array('name'=>'this is nicolas','gender'=>1),
            array('name'=>'this is ada','gender'=>0),
        ),
        'bookMessage'=> array(
            array('name'=>'this is book1','id'=>1),
            array('name'=>'this is book2','id'=>2),
            array('name'=>'this is book3','id'=>3),
            array('name'=>'this is book4','id'=>4),
        ),
    );
    
    $simpleArr = array('cc','dd','ee');
    $dyadicArr = array(
        array('ff','gg','hh'),
        'key'=>array('ii','jj','kk'),
    );
    $keyArr = array(
        'aa'=>'AA',
        'bb'=>'BB',
        'cc'=>'cc',
    );

    $userMessage = array(
        array('name'=>'this is johnny','gender'=>1),
        array('name'=>'this is lei','gender'=>1),
        array('name'=>'this is nicolas','gender'=>1),
        array('name'=>'this is ada','gender'=>0),
    );
    $gender = 0;
    $minismarty->assign('webname', $webname);
    $minismarty->assign('message', $message);
    $minismarty->assign('message1', $message1);
    $minismarty->assign('userMessage', $userMessage);
    $minismarty->assign('simpleArr', $simpleArr);
    $minismarty->assign('dyadicArr', $dyadicArr);
    $minismarty->assign('keyArr', $keyArr);
    $minismarty->assign('gender', $gender);
    //启动编译模板文件
    $minismarty->display('demo.tpl.html');


MySmarty/MySmarty.class.php

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)) {
            $compile = new MySmartyCompile($tpl_file);
            $compile->parse($parse_file);
        }
        // 如果缓存没有开启
        if (!$this->caching) {
            include $parse_file;
            return ;
        }
        
        //开启了缓存才加载缓存文件,否则直接加载编译文件
        //缓存文件
        $cache_file = $this->cache_dir.'/'.md5($file).$file;
        //只有当缓存文件不存在,或者编译文件已被修改过
        //重新生成缓存文件
        if (!file_exists($cache_file) || filemtime($cache_file) < filemtime($parse_file)) {
            ob_start();
            //引入缓存文件
            include $parse_file;
            //缓存内容
            $content = ob_get_contents();
            ob_end_clean();
            //生成缓存文件
            if (!file_put_contents($cache_file, $content)) {
                exit('缓存文件生成出错!');
            }
        }
        //载入缓存文件
        include $cache_file;
    }
}


MySmarty/MySmartyCompile.class.php

content = file_get_contents($tpl_file);
    }
    

    //解析普通变量,如把{$name}解析成$this->_tpl_var['name']
    public function replaceSimpleVar() {
        /**
         * 这个正则表达式是指匹配简单变量
         * 不匹配$xxx.或者$xxx[或者$xxx]既不匹配对象和数组
         * 也不匹配关键字,比如{foreach}等等
         */
        $pattern = '/\{\$(\w+(?!\.|\[|\]))\}/';
        if (preg_match($pattern, $this->content)) {
            $this->content = preg_replace($pattern, '_tpl_var["$1"]?>', $this->content);
        }
    }
    
    public function replaceVar() {
        /**
         *   $webname.name.cc.dd
         *   $webname.name.cc[1].dd
         *   $author[1][12].name[0]
         *   $title[1]
         *   $title.dd
         *   $title.dd[1]
         */
        // \$(\w+(\.|(\[\d+\])+)+)+(\w+(\[\d+\])?)?
        // \$((\w+(\.|(\[\d+\])+)+)+(\w+(\[\d+\])?)?)
//        $pattern = '/\{\$((\w+(\.|(\[\d+\])+)+)+(\w+(\[\d+\])?)?)\}/';
        $pattern = '/\{\$([^\{\}]+)\}/';
        $matches = array();
        preg_match_all($pattern, $this->content,$matches);
        for($i = 0; $i < count($matches[1]); $i++) {
            $str = $this->parseVar($matches[1][$i]);
            $str = "";
            $this->content = str_replace($matches[0][$i], $str, $this->content);
        }
    }
    

    /**
     * 传进来的是一个变量的字串,比如$name,$name[1],$message.name[2]之内的
     * 把这个字符串转化成我们的$this->_tpl_var开头的变量
     * 比如$name => $this->_tpl_var['name']
     * $name[1] =>$this->_tpl_var['name'][1]
     * $message.name[2] => $this->_tpl_var['message']['name'][2]
     * 返回传化后的字符串
     * @param type $arrStr
     * @return str
     */
    public function parseVar($arrStr) {
        
        $str = '$this->_tpl_var';
        $explodeFlag = '.';
        $subStr = explode($explodeFlag, $arrStr);
        for ($i = 0; $i < count($subStr); $i++) {
            $pattern = '/(\w+)((\[\d+\])+)/';
            if(!preg_match($pattern, $subStr[$i], $matches)) {
                $str .= "["."'".$subStr[$i]."'"."]";
                continue;   
            }
            $str .= "["."'".$matches[1]."'"."]".$matches[2];
        }
        return $str;
    }
    
    /**
     * 这个函数的作用是替换模板文件中的foreach语句块,和if语句块
     */
    public function replaceSpecialWords() {
        /**
         * 这个正则表达式匹配{{XXX}}里面的东西,既if语句块和foreach语句块
         * 这个xxx不能包含{{
         * 如果这个语句块是if,那个就要以{/if}结尾,如果是foreach,那么就以{/foreach}结尾
         */
        $pattern = '/\{(\{(\w+)(?:(?!\{\{).|\n)+\{\/\2\})\}/';
        $matches = array();

        preg_match_all($pattern, $this->content, $matches);
        for($i = 0; $i < count($matches[1]);$i++) {
            $str = $this->parseSpecialWords($matches[1][$i]);
            $this->content = str_replace($matches[0][$i], $str, $this->content);
        }
    }

    public function parseSpecialWords($str) {
        /**
         * 匹配出{}或是{{}或是{}}里面的字符串
         */
        $pattern = '/\{([^\{\}]+)\}/';
        preg_match_all($pattern, $str, $matches);
        /**
         * 匹配出第一行里面的变量,并且将他替换掉
         */
        $reg = '/\((\$([^\s]+))/';
        preg_match($reg, $matches[0][0], $var);
        $tmp = $this->parseVar($var[2]);
        $matches[1][0] = str_replace($var[1], $tmp, $matches[1][0]);
        /**
         * flag用来记录这个foreach语句还是if语句块
         * flag = fo or if
         */
        $flag = substr($matches[1][0], 0,2);
        /**
         * replace 根据每一行情况不同,赋不同的php语句,替换掉伪代码
         */
        $replace = '';
        $count = count($matches[1]);
        for ($i = 0; $i < $count; $i++) {
            /**
             * 匹配循环里面需要输出的变量
             */
            $reg1 = '/^\$\w+$/';
            if (preg_match($reg1, $matches[1][$i])) {
                /**
                 * 找到需要输出的变量
                 */
                $replace = "";
            } else if($matches[1][$i] == $matches[1][$count-1] || substr($matches[1][$i],0,1) == '/'){
                /**
                 * 找到结束的地方,用}替换掉
                 */
                $replace = "";
            } else if(substr($matches[1][$i],0,4) == 'else'){
                /**
                 * 如果是else开头,那么应该在else前面加上一个}然后再在语句后面加上一个{
                 */
                $replace = "";
            } else if($flag == 'if' && substr($matches[1][$i],0,2) == 'fo'){
                /**
                 * 这种情况是if语句块里面嵌套foreach语句,因为if的条件变量和foreach的循环变量一般不会相同所以要特殊考虑
                 * 既如果用一个flag来控制if怎么走,然后foreach里面的循环变量数组如果是message,那么我们得要找到message的值
                 */
                //示例字符串foreach ($dyadicArr as $value) 
                $reg = '/\((\$([^\s]+))/';
                preg_match($reg, $matches[0][$i], $var);
                $tmp = $this->parseVar($var[2]);
                $matches[1][$i] = str_replace($var[1], $tmp, $matches[1][$i]);
                $flag = 'fo';
                $replace = "";
            } else {
                /**
                 * 找到循环开始的地方,应该在语句后面加上一个{
                 */
                $replace = "";
            }
            $str = str_replace($matches[0][$i], $replace, $str);
        }
       return $str;
    }
    
    //模板编译
    public function parse($parse_file) {
        ini_set('pcre.backtrack_limit', -1);
//        ini_set('pcre.recursion_limit', 99999);
        //解析foreach和if语句块
        $this->replaceSpecialWords();
        //解析变量
        $this->replaceVar();
        //编译完成后,生成编译文件
        
        if (!file_put_contents($parse_file, $this->content)) {
            exit('编译文件生成出错!');
        }
    }
}


templates/demo.tpl.html


    
        TODO supply a title
        
        
    
    
        

**********这个是一个简单变量**************

{$webname}

**********这是一个数组里面的元素************

{$message[1].friendMessage[1][0]}

*************这里是一个If语句块***********

{{if($gender == 1)}

male

{else}

female

{/if}}

***************这里是一个简单的for循环**************

{{foreach ($dyadicArr as $value)} {foreach ($value as $v)}

{$v}

{/foreach} {/foreach}}

*************这是foreach循环里面嵌套一个If语句块********

{{foreach ($userMessage[1] as $k => $v)} {if($v == 1)}

{$k} => male

{else if($v == 0)}

{$k} => female

{else }

{$k} => {$v}

{/if} {/foreach}}

*******这里是3重foreach语句块嵌套********

{{foreach ($message1 as $key1 => $value1)} {$key1} => {foreach ($value1 as $key2 => $value2)} {foreach ($value2 as $key3 => $value3)}

{$key3}=>{$value3}

{/foreach} {/foreach} {/foreach}}


你可能感兴趣的:(正则表达式,php,smarty)