接上(2)
检测所有模版引擎的语句,发现错误和不对的就产生错误!
成员变量:
- 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);
- }
- }
- 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;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;200px;font-size:12px;text-align:center;color:#800;">恭喜:模版没有错误</div>';
- }
- }
这个方法有点复杂,所以我会一步步说明的:
(1)
- if(strpos($this->template, '{#}') !== false) {
- if(!preg_match("/\{#\}[^({#})]*\{#\}/", $this->template)) {
- exit('错误:{#}没有关闭');
- }
- }
这个语句的用途是检测是否关闭了注释语句,如果没有关闭就强行退出检测!这个检测很简单,就是如果存在{#}但是不存在{#}……{#}就表示没有关闭注释语句。
(2)
- $this->template = explode("\n", $this->template);
这个语句是用来把模版内容按换行来分割成数组。
(3)
- $line_number = 1;
- foreach($this->template as $line) {
(4)
- 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}的,并保存行数到ENDIF _LINE_NUM变量中;
如此类推:
- 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;
- }
(5)
- if(strpos($line, "{include") !== false) {
- if(!preg_match("/\{include \"[^}]*\"\}/", $line)) {
- $this->ERRORS[] = '错误:INCLUDE语法使用错误,在行<font color="red">'.$line_number.'</font>';
- }
- }
上面是检测include语法是否正确(是否符合{include “……”})。
(6)
- $this->check_if();
- $this->check_foreach();
调用上面的两个方法;这两个方法是用来检测if和foreach是否嵌套合理和是否关闭了。
check_if()方法:
- 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>';
- }
- }
- }
从上面的代码可以看出,我们主要是根据IF和ENDIF的函数和数量来判断是否嵌套正确和关闭的!假如EndIF的行数位置比IF要高,就说明没有IF就使用ENDIF了!加入ENDIF和IF的数量不一样,就说明IF没有关闭!!
Check_foreach()方法:
- 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>';
- }
- }
- }
Check_forech()方法的原来个check_if()方法一样!!
(7)
- if(count($this->ERRORS) > 0) {
- echo '<div style="border:1px solid #f60;padding:10px;500px;font-size:12px;color:#800;">';
- foreach($this->ERRORS as $e) {
- echo $e, '<br/>';
- }
- echo '</div>';
- }
最后就是highlight_html()方法:
- 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;
- }
这个方法主要是用来高亮HTML标签的!!在上面那个start()方法中会使用的这个方法!
至此,我们的模版引擎就完成了!
- <?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;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;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;
- }
- }