php 教你写自己的模版引擎三

终极篇――Debug篇

故事到了尾声了!!废话就不多说了!开始~

先说说这个类原理吧:其实很简单,检测所有模版引擎的语句,发现错误和不对的就产生错误!

成员变量:

private $template; //用来保存模版的内容
private $IF_LINE_NUM; //用来保存IF所在的行数
private $ENDIF_LINE_NUM; //用来保存ENDIF所在的行数
private $FOREACH_LINE_NUM; //用来保存FOREACH所在的行数
private $ENDFOREACH_LINE_NUM; //用来保存ENDFOREACH所在的行数
private $ERRORS; //用来保存错误信息


构造函数:

public function __construct($file_name = NULL) {
        if(isset($file_name) && trim($file_name) != '') {
                $this->set_file($file_name);
        }
}

set_file()方法主要是用来打开模版文件和读取文件内容的:

public function set_file($file_name) {
        $file_name = TPL_DIR.$file_name;
        if(file_exists($file_name)) {
                $fp = fopen($file_name, 'r') OR exit('错误:不能打开模板文件');
                if(($fs = filesize($file_name)) > 0)
                $this->template = fread($fp, $fs);
                fclose($fp);
                return true;
        }
        exit('错误:模板文件不存在');
}

然后就是到最重要的start方法:
[php]
function start($display = FALSE) {
        if(strpos($this->template, '{#}') !== false) {
                if(!preg_match("/\{#\}[^({#})]*\{#\}/", $this->template)) {
                        exit('错误:{#}没有关闭');
                }
        }
        $this->template = explode("\n", $this->template);
               
        $line_number = 1;
        foreach($this->template as $line) {
                if(trim($line) != '') {
                        if(preg_match("/\{\s*if/", $line)) {
                                $this->IF_LINE_NUM[] = $line_number;
                        }
                        if(preg_match("/\{\s*\/if\s*\}/", $line)) {
                                $this->ENDIF_LINE_NUM[] = $line_number;
                        }
                        
                                if(preg_match("/\{\s*\\$[0-9a-zA-Z_]+\->foreach\(\s*[0-9a-zA-Z_]+\s*,\s*[0-9a-zA-Z_]+\s*\)\s*\}/", $line)) {
                                $this->FOREACH_LINE_NUM[] = $line_number;
                        }
                                
                        if(preg_match("/\{\s*\/foreach\s*\}/", $line)) {
                                $this->ENDFOREACH_LINE_NUM[] = $line_number;
                        }
                                
                        if(strpos($line, "{include") !== false) {
                                if(!preg_match("/\{include \"[^}]*\"\}/", $line)) {
                                        $this->ERRORS[] = '错误:INCLUDE语法使用错误,在行<font color="red">'.$line_number.'</font>';
                                }
                        }
                }
                $line_number++;
        }
        $this->check_if();
        $this->check_foreach();
        if(count($this->ERRORS) > 0) {
                echo '<div style="border:1px solid #f60;padding:10px;width:500px;font-size:12px;color:#800;">';
                foreach($this->ERRORS as $e) {
                        echo $e, '<br/>';
                }
                echo '</div>';
        } else {
                if($display)
                        echo $this->highlight_html(implode('',$this->template));
                echo '<div style="border:1px solid #f60;padding:10px;width:200px;font-size:12px;text-align:center;color:#800;">恭喜:模版没有错误</div>';
        }
}
[/php]
这个方法有点复杂,所以我会一步步说明的:
(1)
[php]if(strpos($this->template, '{#}') !== false) {
        if(!preg_match("/\{#\}[^({#})]*\{#\}/", $this->template)) {
                exit('错误:{#}没有关闭');
        }
}[/php]
这个语句的用途是检测是否关闭了注释语句,如果没有关闭就强行退出检测!这个检测很简单,就是如果存在{#}但是不存在{#}……{#}就表示没有关闭注释语句。

(2)
$this->template = explode("\n", $this->template);
这个语句是用来把模版内容按换行来分割成数组。

(3)

$line_number = 1;
        foreach($this->template as $line) {
这里是循环数组。

(4)
[php]if(preg_match("/\{\s*if/", $line)) {
        $this->IF_LINE_NUM[] = $line_number;
}[/php]
上面是匹配{if}语句的,并保存行数到IF_LINE_NUM变量中;

[php]if(preg_match("/\{\s*\/if\s*\}/", $line)) {
        $this->ENDIF_LINE_NUM[] = $line_number;
}[/php]
上面是匹配{/if}的,并保存行数到ENDIF _LINE_NUM变量中;

如此类推:
[php]
if(preg_match("/\{\s*\\$[0-9a-zA-Z_]+\->foreach\(\s*[0-9a-zA-Z_]+\s*,\s*[0-9a-zA-Z_]+\s*\)\s*\}/", $line)) {
        $this->FOREACH_LINE_NUM[] = $line_number;
}                                
if(preg_match("/\{\s*\/foreach\s*\}/", $line)) {
        $this->ENDFOREACH_LINE_NUM[] = $line_number;
}
[/php]
(5)
[php]
if(strpos($line, "{include") !== false) {
        if(!preg_match("/\{include \"[^}]*\"\}/", $line)) {
                $this->ERRORS[] = '错误:INCLUDE语法使用错误,在行<font color="red">'.$line_number.'</font>';
                }
}
[/php]
上面是检测include语法是否正确(是否符合{include “……”})。

(6)

$this->check_if();
$this->check_foreach();

调用上面的两个方法;这两个方法是用来检测if和foreach是否嵌套合理和是否关闭了。


check_if()方法:
[php]
private function check_if() {
                $ifs = count($this->IF_LINE_NUM);
                for($i = 0 ; $i < $ifs ; $i++) {
                        if(isset($this->ENDIF_LINE_NUM[$i])) {
                                if($this->IF_LINE_NUM[$i] > $this->ENDIF_LINE_NUM[$i]) {
                                        $this->ERRORS[] = '错误:在没有IF的情况下使用END IF,在行<font color="red">'.$this->ENDIF_LINE_NUM[$i].'</font>';
                                }
                        } else {
                                $this->ERRORS[] = '错误:IF没有关闭,在行<font color="red">'.$this->IF_LINE_NUM[$i].'</font>';
                        }
                }
                if(count($this->IF_LINE_NUM) == 0 && count($this->ENDIF_LINE_NUM) > 0) {
                        foreach($this->ENDIF_LINE_NUM as $line_number) {
                                $this->ERRORS[] = '错误:在没有IF的情况下使用END IF,在行<font color="red">'.$line_number.'</font>';
                        }
                }
        }
[/php]
从上面的代码可以看出,我们主要是根据IF和ENDIF的函数和数量来判断是否嵌套正确和关闭的!假如EndIF的行数位置比IF要高,就说明没有IF就使用ENDIF了!加入ENDIF和IF的数量不一样,就说明IF没有关闭!!

Check_foreach()方法:
[php]
private function check_foreach() {
                $foreachs = count($this->FOREACH_LINE_NUM);
                for($i = 0 ; $i < $foreachs ; $i++) {
                        if(isset($this->ENDFOREACH_LINE_NUM[$i])) {
                                if($this->FOREACH_LINE_NUM[$i] > $this->ENDFOREACH_LINE_NUM[$i]) {
                                        $this->ERRORS[] = '错误:在没有FOREACH的情况下使用END FOREACH,在行<font color="red">'.$this->ENDFOREACH_LINE_NUM[$i].'</font>';
                                }
                        } else {
                                $this->ERRORS[] = '错误:FOREACH没有关闭,在行<font color="red">'.$this->FOREACH_LINE_NUM[$i].'</font>';
                        }
                }
                if(count($this->FOREACH_LINE_NUM) == 0 && count($this->ENDFOREACH_LINE_NUM) > 0) {
                        foreach($this->ENDFOREACH_LINE_NUM as $line_number) {
                                $this->ERRORS[] = '错误:在没有FOREACH的情况下使用END FOREACH,在行<font color="red">'.$line_number.'</font>';
                        }
                }
        }
[/php]
Check_forech()方法的原来个check_if()方法一样!!

(6)

if(count($this->ERRORS) > 0) {
                echo '<div style="border:1px solid #f60;padding:10px;width:500px;font-size:12px;color:#800;">';
                foreach($this->ERRORS as $e) {
                        echo $e, '<br/>';
                }
                echo '</div>';
        }

这里是显示错误的!!

最后就是highlight_html()方法:
[php]
private function highlight_html($code)        {
                $code  = str_replace('<', '<', $code);
                $code  = str_replace('>', '>', $code);
                $code  =  preg_replace('/([a-zA-Z_]+)=/',  '<font color="#FF0000">$1=</font>',  $code);
                $code  =  preg_replace('/(<[\/a-zA-Z0-9&;]+)/',  '<font color="#0000FF">$1</font>',  $code);
                $code  =  str_replace('<!--',  '<font color="#008080"><!--',  $code);
                $code  =  str_replace('-->',  '--></font>',  $code);
                $code  =  preg_replace('/[\r\n]+/',  "\n",  $code);
                $code  = nl2br($code);
                return $code;
        }
[/php]
这个方法主要是用来高亮HTML标签的!!在上面那个start()方法中会使用的这个方法!

至此,我们的模版引擎就完成了!谢谢大家一直以来的支持!!祝大家圣诞节快乐!!

Show show全相:
[php]
<?php
/**
*
* @author :PHP毛毛虫
* @copyright :2008-12-24圣诞节
*
*/
class StupidDebuger {
        private $template;
        private $IF_LINE_NUM;
        private $ENDIF_LINE_NUM;
        private $FOREACH_LINE_NUM;
        private $ENDFOREACH_LINE_NUM;
        private $ERRORS;
        
        public function __construct($file_name = NULL) {
                if(isset($file_name) && trim($file_name) != '') {
                        $this->set_file($file_name);
                }
        }
        
        public function set_file($file_name) {
                $file_name = TPL_DIR.$file_name;
                if(file_exists($file_name)) {
                        $fp = fopen($file_name, 'r') OR exit('错误:不能打开模板文件');
                        if(($fs = filesize($file_name)) > 0)
                        $this->template = fread($fp, $fs);
                        fclose($fp);
                        return true;
                }
                exit('错误:模板文件不存在');
        }
        
        function start($display = FALSE) {
                if(strpos($this->template, '{#}') !== false) {
                        if(!preg_match("/\{#\}[^({#})]*\{#\}/", $this->template)) {
                                exit('错误:{#}没有关闭');
                        }
                }
                $this->template = explode("\n", $this->template);
               
                $line_number = 1;
                foreach($this->template as $line) {
                        if(trim($line) != '') {
                                if(preg_match("/\{\s*if/", $line)) {
                                        $this->IF_LINE_NUM[] = $line_number;
                                }
                                if(preg_match("/\{\s*\/if\s*\}/", $line)) {
                                        $this->ENDIF_LINE_NUM[] = $line_number;
                                }
                        
                                if(preg_match("/\{\s*\\$[0-9a-zA-Z_]+\->foreach\(\s*[0-9a-zA-Z_]+\s*,\s*[0-9a-zA-Z_]+\s*\)\s*\}/", $line)) {
                                        $this->FOREACH_LINE_NUM[] = $line_number;
                                }
                                
                                if(preg_match("/\{\s*\/foreach\s*\}/", $line)) {
                                        $this->ENDFOREACH_LINE_NUM[] = $line_number;
                                }
                                
                                if(strpos($line, "{include") !== false) {
                                        if(!preg_match("/\{include \"[^}]*\"\}/", $line)) {
                                                $this->ERRORS[] = '错误:INCLUDE语法使用错误,在行<font color="red">'.$line_number.'</font>';
                                        }
                                }
                        }
                        $line_number++;
                }
                $this->check_if();
                $this->check_foreach();
                if(count($this->ERRORS) > 0) {
                        echo '<div style="border:1px solid #f60;padding:10px;width:500px;font-size:12px;color:#800;">';
                        foreach($this->ERRORS as $e) {
                                echo $e, '<br/>';
                        }
                        echo '</div>';
                } else {
                        if($display)
                                echo $this->highlight_html(implode('',$this->template));
                        echo '<div style="border:1px solid #f60;padding:10px;width:200px;font-size:12px;text-align:center;color:#800;">恭喜:模版没有错误</div>';
                }
        }
        
        private function check_if() {
                $ifs = count($this->IF_LINE_NUM);
                for($i = 0 ; $i < $ifs ; $i++) {
                        if(isset($this->ENDIF_LINE_NUM[$i])) {
                                if($this->IF_LINE_NUM[$i] > $this->ENDIF_LINE_NUM[$i]) {
                                        $this->ERRORS[] = '错误:在没有IF的情况下使用END IF,在行<font color="red">'.$this->ENDIF_LINE_NUM[$i].'</font>';
                                }
                        } else {
                                $this->ERRORS[] = '错误:IF没有关闭,在行<font color="red">'.$this->IF_LINE_NUM[$i].'</font>';
                        }
                }
                if(count($this->IF_LINE_NUM) == 0 && count($this->ENDIF_LINE_NUM) > 0) {
                        foreach($this->ENDIF_LINE_NUM as $line_number) {
                                $this->ERRORS[] = '错误:在没有IF的情况下使用END IF,在行<font color="red">'.$line_number.'</font>';
                        }
                }
        }
        
        private function check_foreach() {
                $foreachs = count($this->FOREACH_LINE_NUM);
                for($i = 0 ; $i < $foreachs ; $i++) {
                        if(isset($this->ENDFOREACH_LINE_NUM[$i])) {
                                if($this->FOREACH_LINE_NUM[$i] > $this->ENDFOREACH_LINE_NUM[$i]) {
                                        $this->ERRORS[] = '错误:在没有FOREACH的情况下使用END FOREACH,在行<font color="red">'.$this->ENDFOREACH_LINE_NUM[$i].'</font>';
                                }
                        } else {
                                $this->ERRORS[] = '错误:FOREACH没有关闭,在行<font color="red">'.$this->FOREACH_LINE_NUM[$i].'</font>';
                        }
                }
                if(count($this->FOREACH_LINE_NUM) == 0 && count($this->ENDFOREACH_LINE_NUM) > 0) {
                        foreach($this->ENDFOREACH_LINE_NUM as $line_number) {
                                $this->ERRORS[] = '错误:在没有FOREACH的情况下使用END FOREACH,在行<font color="red">'.$line_number.'</font>';
                        }
                }
        }
        
        private function highlight_html($code)        {
                $code  = str_replace('<', '<', $code);
                $code  = str_replace('>', '>', $code);
                $code  =  preg_replace('/([a-zA-Z_]+)=/',  '<font color="#FF0000">$1=</font>',  $code);
                $code  =  preg_replace('/(<[\/a-zA-Z0-9&;]+)/',  '<font color="#0000FF">$1</font>',  $code);
                $code  =  str_replace('<!--',  '<font color="#008080"><!--',  $code);
                $code  =  str_replace('-->',  '--></font>',  $code);
                $code  =  preg_replace('/[\r\n]+/',  "\n",  $code);
                $code  = nl2br($code);
                return $code;
        }
}
[/php]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值