写一个属于自己的模板引擎(3)

接上(2)

检测所有模版引擎的语句,发现错误和不对的就产生错误!
成员变量:

  1. private $template//用来保存模版的内容
  2. private $IF_LINE_NUM//用来保存IF所在的行数
  3. private $ENDIF_LINE_NUM//用来保存ENDIF所在的行数
  4. private $FOREACH_LINE_NUM//用来保存FOREACH所在的行数
  5. private $ENDFOREACH_LINE_NUM//用来保存ENDFOREACH所在的行数
  6. private $ERRORS//用来保存错误信息


构造函数:

  1. public function __construct($file_name NULL) {
  2.         if(isset($file_name) && trim($file_name) != '') {
  3.                 $this->set_file($file_name);
  4.         }
  5. }
set_file()方法主要是用来打开模版文件和读取文件内容的:
  1. public function set_file($file_name) {
  2.         $file_name TPL_DIR.$file_name;
  3.         if(file_exists($file_name)) {
  4.                 $fp fopen($file_name'r') OR exit('错误:不能打开模板文件');
  5.                 if(($fs filesize($file_name)) > 0)
  6.                 $this->template fread($fp$fs);
  7.                 fclose($fp);
  8.                 return true;
  9.         }
  10.         exit('错误:模板文件不存在');
  11. }
然后就是到最重要的start方法:
  1. function start($display FALSE) {
  2.         if(strpos($this->template'{#}') !== false) {
  3.                 if(!preg_match("/\{#\}[^({#})]*\{#\}/"$this->template)) {
  4.                         exit('错误:{#}没有关闭');
  5.                 }
  6.         }
  7.         $this->template explode("\n"$this->template);
  8.                 
  9.         $line_number 1;
  10.         foreach($this->template as $line) {
  11.                 if(trim($line) != '') {
  12.                         if(preg_match("/\{\s*if/"$line)) {
  13.                                 $this->IF_LINE_NUM[] = $line_number;
  14.                         }
  15.                         if(preg_match("/\{\s*\/if\s*\}/"$line)) {
  16.                                 $this->ENDIF_LINE_NUM[] = $line_number;
  17.                         }
  18.                         
  19.                                 if(preg_match("/\{\s*\\$[0-9a-zA-Z_]+\->foreach\(\s*[0-9a-zA-Z_]+\s*,\s*[0-9a-zA-Z_]+\s*\)\s*\}/"$line)) {
  20.                                 $this->FOREACH_LINE_NUM[] = $line_number;
  21.                         }
  22.                                 
  23.                         if(preg_match("/\{\s*\/foreach\s*\}/"$line)) {
  24.                                 $this->ENDFOREACH_LINE_NUM[] = $line_number;
  25.                         }
  26.                                 
  27.                         if(strpos($line"{include") !== false) {
  28.                                 if(!preg_match("/\{include \"[^}]*\"\}/"$line)) {
  29.                                         $this->ERRORS[] = '错误:INCLUDE语法使用错误,在行<font color="red">'.$line_number.'</font>';
  30.                                 }
  31.                         }
  32.                 }
  33.                 $line_number++;
  34.         }
  35.         $this->check_if();
  36.         $this->check_foreach();
  37.         if(count($this->ERRORS) > 0) {
  38.                 echo '<div style="border:1px solid #f60;padding:10px;500px;font-size:12px;color:#800;">';
  39.                 foreach($this->ERRORS as $e) {
  40.                         echo $e'<br/>';
  41.                 }
  42.                 echo '</div>';
  43.         } else {
  44.                 if($display)
  45.                         echo $this->highlight_html(implode('',$this->template));
  46.                 echo '<div style="border:1px solid #f60;padding:10px;200px;font-size:12px;text-align:center;color:#800;">恭喜:模版没有错误</div>';
  47.         }
  48. }

这个方法有点复杂,所以我会一步步说明的:
(1)
  1. if(strpos($this->template'{#}') !== false) {
  2.         if(!preg_match("/\{#\}[^({#})]*\{#\}/"$this->template)) {
  3.                 exit('错误:{#}没有关闭');
  4.         }
  5. }


这个语句的用途是检测是否关闭了注释语句,如果没有关闭就强行退出检测!这个检测很简单,就是如果存在{#}但是不存在{#}……{#}就表示没有关闭注释语句。
(2)
  1. $this->template explode("\n"$this->template);

这个语句是用来把模版内容按换行来分割成数组。
(3)
  1. $line_number 1;
  2.         foreach($this->template as $line) {
这里是循环数组。
(4)
  1. if(preg_match("/\{\s*if/"$line)) {
  2.         $this->IF_LINE_NUM[] = $line_number;
  3. }
上面是匹配{if}语句的,并保存行数到IF_LINE_NUM变量中;
  1. if(preg_match("/\{\s*\/if\s*\}/"$line)) {
  2.         $this->ENDIF_LINE_NUM[] = $line_number;
  3. }

上面是匹配{/if}的,并保存行数到ENDIF _LINE_NUM变量中;
如此类推:
  1. if(preg_match("/\{\s*\\$[0-9a-zA-Z_]+\->foreach\(\s*[0-9a-zA-Z_]+\s*,\s*[0-9a-zA-Z_]+\s*\)\s*\}/"$line)) {
  2.         $this->FOREACH_LINE_NUM[] = $line_number;
  3. }                                
  4. if(preg_match("/\{\s*\/foreach\s*\}/"$line)) {
  5.         $this->ENDFOREACH_LINE_NUM[] = $line_number;
  6. }

(5)
  1. if(strpos($line"{include") !== false) {
  2.         if(!preg_match("/\{include \"[^}]*\"\}/"$line)) {
  3.                 $this->ERRORS[] = '错误:INCLUDE语法使用错误,在行<font color="red">'.$line_number.'</font>';
  4.                 }
  5. }

上面是检测include语法是否正确(是否符合{include “……”})。
(6)
  1. $this->check_if();
  2. $this->check_foreach();

调用上面的两个方法;这两个方法是用来检测if和foreach是否嵌套合理和是否关闭了。
check_if()方法:
  1. private function check_if() {
  2.                 $ifs count($this->IF_LINE_NUM);
  3.                 for($i $i $ifs $i++) {
  4.                         if(isset($this->ENDIF_LINE_NUM[$i])) {
  5.                                 if($this->IF_LINE_NUM[$i] > $this->ENDIF_LINE_NUM[$i]) {
  6.                                         $this->ERRORS[] = '错误:在没有IF的情况下使用END IF,在行<font color="red">'.$this->ENDIF_LINE_NUM[$i].'</font>';
  7.                                 }
  8.                         } else {
  9.                                 $this->ERRORS[] = '错误:IF没有关闭,在行<font color="red">'.$this->IF_LINE_NUM[$i].'</font>';
  10.                         }
  11.                 }
  12.                 if(count($this->IF_LINE_NUM) == && count($this->ENDIF_LINE_NUM) > 0) {
  13.                         foreach($this->ENDIF_LINE_NUM as $line_number) {
  14.                                 $this->ERRORS[] = '错误:在没有IF的情况下使用END IF,在行<font color="red">'.$line_number.'</font>';
  15.                         }
  16.                 }
  17.         }

从上面的代码可以看出,我们主要是根据IF和ENDIF的函数和数量来判断是否嵌套正确和关闭的!假如EndIF的行数位置比IF要高,就说明没有IF就使用ENDIF了!加入ENDIF和IF的数量不一样,就说明IF没有关闭!!
Check_foreach()方法:
  1. private function check_foreach() {
  2.                 $foreachs count($this->FOREACH_LINE_NUM);
  3.                 for($i $i $foreachs $i++) {
  4.                         if(isset($this->ENDFOREACH_LINE_NUM[$i])) {
  5.                                 if($this->FOREACH_LINE_NUM[$i] > $this->ENDFOREACH_LINE_NUM[$i]) {
  6.                                         $this->ERRORS[] = '错误:在没有FOREACH的情况下使用END FOREACH,在行<font color="red">'.$this->ENDFOREACH_LINE_NUM[$i].'</font>';
  7.                                 }
  8.                         } else {
  9.                                 $this->ERRORS[] = '错误:FOREACH没有关闭,在行<font color="red">'.$this->FOREACH_LINE_NUM[$i].'</font>';
  10.                         }
  11.                 }
  12.                 if(count($this->FOREACH_LINE_NUM) == && count($this->ENDFOREACH_LINE_NUM) > 0) {
  13.                         foreach($this->ENDFOREACH_LINE_NUM as $line_number) {
  14.                                 $this->ERRORS[] = '错误:在没有FOREACH的情况下使用END FOREACH,在行<font color="red">'.$line_number.'</font>';
  15.                         }
  16.                 }
  17.         }

Check_forech()方法的原来个check_if()方法一样!!

(7)
  1. if(count($this->ERRORS) > 0) {
  2.                 echo '<div style="border:1px solid #f60;padding:10px;500px;font-size:12px;color:#800;">';
  3.                 foreach($this->ERRORS as $e) {
  4.                         echo $e'<br/>';
  5.                 }
  6.                 echo '</div>';
  7.         }
这里是显示错误的!!
最后就是highlight_html()方法:
  1. private function highlight_html($code)        {
  2.                 $code  str_replace('<''<'$code);
  3.                 $code  str_replace('>''>'$code);
  4.                 $code  =  preg_replace('/([a-zA-Z_]+)=/',  '<font color="#FF0000">$1=</font>',  $code);
  5.                 $code  =  preg_replace('/(<[\/a-zA-Z0-9&;]+)/',  '<font color="#0000FF">$1</font>',  $code);
  6.                 $code  =  str_replace('<!--',  '<font color="#008080"><!--',  $code);
  7.                 $code  =  str_replace('-->',  '--></font>',  $code);
  8.                 $code  =  preg_replace('/[\r\n]+/',  "\n",  $code);
  9.                 $code  nl2br($code);
  10.                 return $code;
  11.         }


这个方法主要是用来高亮HTML标签的!!在上面那个start()方法中会使用的这个方法!
至此,我们的模版引擎就完成了!

Show show全相:
  1. <?php
  2. /**
  3. *
  4. * @author :PHP毛毛虫
  5. * @copyright :2008-12-24圣诞节
  6. *
  7. */
  8. class StupidDebuger {
  9.         private $template;
  10.         private $IF_LINE_NUM;
  11.         private $ENDIF_LINE_NUM;
  12.         private $FOREACH_LINE_NUM;
  13.         private $ENDFOREACH_LINE_NUM;
  14.         private $ERRORS;
  15.         
  16.         public function __construct($file_name NULL) {
  17.                 if(isset($file_name) && trim($file_name) != '') {
  18.                         $this->set_file($file_name);
  19.                 }
  20.         }
  21.         
  22.         public function set_file($file_name) {
  23.                 $file_name TPL_DIR.$file_name;
  24.                 if(file_exists($file_name)) {
  25.                         $fp fopen($file_name'r') OR exit('错误:不能打开模板文件');
  26.                         if(($fs filesize($file_name)) > 0)
  27.                         $this->template fread($fp$fs);
  28.                         fclose($fp);
  29.                         return true;
  30.                 }
  31.                 exit('错误:模板文件不存在');
  32.         }
  33.         
  34.         function start($display FALSE) {
  35.                 if(strpos($this->template'{#}') !== false) {
  36.                         if(!preg_match("/\{#\}[^({#})]*\{#\}/"$this->template)) {
  37.                                 exit('错误:{#}没有关闭');
  38.                         }
  39.                 }
  40.                 $this->template explode("\n"$this->template);
  41.                 
  42.                 $line_number 1;
  43.                 foreach($this->template as $line) {
  44.                         if(trim($line) != '') {
  45.                                 if(preg_match("/\{\s*if/"$line)) {
  46.                                         $this->IF_LINE_NUM[] = $line_number;
  47.                                 }
  48.                                 if(preg_match("/\{\s*\/if\s*\}/"$line)) {
  49.                                         $this->ENDIF_LINE_NUM[] = $line_number;
  50.                                 }
  51.                         
  52.                                 if(preg_match("/\{\s*\\$[0-9a-zA-Z_]+\->foreach\(\s*[0-9a-zA-Z_]+\s*,\s*[0-9a-zA-Z_]+\s*\)\s*\}/"$line)) {
  53.                                         $this->FOREACH_LINE_NUM[] = $line_number;
  54.                                 }
  55.                                 
  56.                                 if(preg_match("/\{\s*\/foreach\s*\}/"$line)) {
  57.                                         $this->ENDFOREACH_LINE_NUM[] = $line_number;
  58.                                 }
  59.                                 
  60.                                 if(strpos($line"{include") !== false) {
  61.                                         if(!preg_match("/\{include \"[^}]*\"\}/"$line)) {
  62.                                                 $this->ERRORS[] = '错误:INCLUDE语法使用错误,在行<font color="red">'.$line_number.'</font>';
  63.                                         }
  64.                                 }
  65.                         }
  66.                         $line_number++;
  67.                 }
  68.                 $this->check_if();
  69.                 $this->check_foreach();
  70.                 if(count($this->ERRORS) > 0) {
  71.                         echo '<div style="border:1px solid #f60;padding:10px;500px;font-size:12px;color:#800;">';
  72.                         foreach($this->ERRORS as $e) {
  73.                                 echo $e'<br/>';
  74.                         }
  75.                         echo '</div>';
  76.                 } else {
  77.                         if($display)
  78.                                 echo $this->highlight_html(implode('',$this->template));
  79.                         echo '<div style="border:1px solid #f60;padding:10px;200px;font-size:12px;text-align:center;color:#800;">恭喜:模版没有错误</div>';
  80.                 }
  81.         }
  82.         
  83.         private function check_if() {
  84.                 $ifs count($this->IF_LINE_NUM);
  85.                 for($i $i $ifs $i++) {
  86.                         if(isset($this->ENDIF_LINE_NUM[$i])) {
  87.                                 if($this->IF_LINE_NUM[$i] > $this->ENDIF_LINE_NUM[$i]) {
  88.                                         $this->ERRORS[] = '错误:在没有IF的情况下使用END IF,在行<font color="red">'.$this->ENDIF_LINE_NUM[$i].'</font>';
  89.                                 }
  90.                         } else {
  91.                                 $this->ERRORS[] = '错误:IF没有关闭,在行<font color="red">'.$this->IF_LINE_NUM[$i].'</font>';
  92.                         }
  93.                 }
  94.                 if(count($this->IF_LINE_NUM) == && count($this->ENDIF_LINE_NUM) > 0) {
  95.                         foreach($this->ENDIF_LINE_NUM as $line_number) {
  96.                                 $this->ERRORS[] = '错误:在没有IF的情况下使用END IF,在行<font color="red">'.$line_number.'</font>';
  97.                         }
  98.                 }
  99.         }
  100.         
  101.         private function check_foreach() {
  102.                 $foreachs count($this->FOREACH_LINE_NUM);
  103.                 for($i $i $foreachs $i++) {
  104.                         if(isset($this->ENDFOREACH_LINE_NUM[$i])) {
  105.                                 if($this->FOREACH_LINE_NUM[$i] > $this->ENDFOREACH_LINE_NUM[$i]) {
  106.                                         $this->ERRORS[] = '错误:在没有FOREACH的情况下使用END FOREACH,在行<font color="red">'.$this->ENDFOREACH_LINE_NUM[$i].'</font>';
  107.                                 }
  108.                         } else {
  109.                                 $this->ERRORS[] = '错误:FOREACH没有关闭,在行<font color="red">'.$this->FOREACH_LINE_NUM[$i].'</font>';
  110.                         }
  111.                 }
  112.                 if(count($this->FOREACH_LINE_NUM) == && count($this->ENDFOREACH_LINE_NUM) > 0) {
  113.                         foreach($this->ENDFOREACH_LINE_NUM as $line_number) {
  114.                                 $this->ERRORS[] = '错误:在没有FOREACH的情况下使用END FOREACH,在行<font color="red">'.$line_number.'</font>';
  115.                         }
  116.                 }
  117.         }
  118.         
  119.         private function highlight_html($code)        {
  120.                 $code  str_replace('<''<'$code);
  121.                 $code  str_replace('>''>'$code);
  122.                 $code  =  preg_replace('/([a-zA-Z_]+)=/',  '<font color="#FF0000">$1=</font>',  $code);
  123.                 $code  =  preg_replace('/(<[\/a-zA-Z0-9&;]+)/',  '<font color="#0000FF">$1</font>',  $code);
  124.                 $code  =  str_replace('<!--',  '<font color="#008080"><!--',  $code);
  125.                 $code  =  str_replace('-->',  '--></font>',  $code);
  126.                 $code  =  preg_replace('/[\r\n]+/',  "\n",  $code);
  127.                 $code  nl2br($code);
  128.                 return $code;
  129.         }
  130. }
原文地址:https://www.cnblogs.com/kuyuecs/p/1390633.html