自己用的一款模板解析程序V0.1(支持插件和扩展)(思路讨论和使用体验)
前阶段,有个项目需要使用php,于是组了一个3人组团队进行开发。
在项目中使用了模板解析,首先申明一下,个人认为:
1、模板解析并不是只有cms才用,中小型企业或者政府应用软件 尤其OA这样的自动化系统也是非常适用的。
2、如果运用于网站 则更主要的是模板解析速度和性能,如果应用于软件,更重要的是方便、可复用性强、可移植性强(这点尤其重要)
3、模板解析说到底就是变量替换,然而网页不比固定的软件界面,会产生的各种情况太多太复杂,因此不建议使用国外的很复杂的模板引擎,虽说开源但里面的代码非高手很难读懂,就算读得懂,也没有这么多时间去读和修改。(国内程序员大部分人都“没时间”,你懂得!!!)
4、模板解析过程中往往需要一些自定义函数,国外的如果要修改主程序比较复杂,依然是没时间。
因此让团队成员花了点时间开发了这个模板解析程序,我试了一下效果还可以,性能一般吧,不过我们是用在中小型企业应用里面的.
企业应用比较繁琐的就是表单,而且领导对表单的要求比较高,口味也很重,同样一个表的操作,新增和修改界面就要不一样,因此使用模板来加载数据是首选.
该模板解析程序功能比较简单 在后台进行数据绑定后,前台可以无限嵌套循环数据 ,个人比较喜欢的是,支持代码插件,譬如我想在页面中支持if else 判断,便可以自己写个解析程序加载进去,进行解析,同时在还支持了 自定义函数,函数的编写直接使用php代码即可。 以下我做一个说明
首先页面模板如下:
<?php class plugin_IF_ //插件类 { var $tag="/\<plugin:IF\>(.*?)\<\/plugin:IF\>/s"; function getLineCnt($begin,$end,$else,$list,$istrue) { if($begin==$end || $begin>$end || $begin<0) return "";//标签必须分行写 否则返回空 $ret=""; for($i=0;$i<=count($list)-1;$i++) { if($istrue) { $tmp=$list[$i]; if($else>0) { if($i>$else && $i<$end) continue; } if($i==$begin) { $tmp=preg_replace("/<!--if\((.*?)\)-->/s","",$tmp); } if($i==$end) { $tmp=preg_replace("/<!--endif-->/s","",$tmp); } if($i==$else) $tmp=preg_replace("/<!--else-->/s","",$tmp); if(trim($tmp)!="") $ret.=chr(13).$list[$i]; } else //非正确匹配 则要排除 begin 到end以外的 内容 { if($i<$begin || $i>$end || ($else>0 && $i>$else && $i<$end)) { $tmp=$list[$i]; if($i==$begin) $tmp=preg_replace("/<!--if\((.*?)\)-->/s","",$tmp); if($i==$end) $tmp=preg_replace("/<!--endif-->/s","",$tmp); if($i==$else) $tmp=preg_replace("/<!--else-->/s","",$tmp); if(trim($tmp)!="") $ret.=chr(13).$tmp; } } } return $ret; } function execFunc($cnt) { $list=explode(chr(13),$cnt); if(count($list)<2) return false;//必须有2行 否则 认为没有条件判读 $copy=array_reverse($list); $firstIF=""; $elseLinenum=0; $hasEndif=false; $beginLinenum=0; $endLinenum=0; $i=0; foreach($list as $line) { if(preg_match("/<!--if\((.*?)\)-->/s",$line,$match) && $firstIF=="")//代表匹配到第一个if 语句 { if($match && count($match)>1) { $firstIF=trim($match[1]); $beginLinenum=$i; } } if(preg_match("/<!--else-->/s",$line,$match) && $elseLinenum==0)//代表匹配到第一个else 语句 { $elseLinenum=$i; } if($firstIF!="" && $elseLinenum>0) break;//节省循环次数 $i++; } if(trim($firstIF)=="") return false;//没有开始标记 则认为没有代码 $i=count($list)-1; foreach($copy as $line) { if(preg_match("/<!--endif-->/s",$line))//代表匹配到最后一个if 语句 { $hasEndif=true; $endLinenum=$i; break; } $i--; } if(!$hasEndif) return false; //标签写错 则认为没有if判断 try { eval("\$ifvalue=(".$firstIF.");"); if(isset($ifvalue)) { if($ifvalue)//判断为true 则要获取所有内容 { return $this->getLineCnt($beginLinenum,$endLinenum,$elseLinenum,$list,true); } else return $this->getLineCnt($beginLinenum,$endLinenum,$elseLinenum,$list,false); } else return "";//条件判断写错 会 清除所有内容 } catch(Exception $ex) { return "";//代码发生未知错误 也会 清除所有内容 } } function getIfList($cnt) { preg_match_all($this->tag,$cnt,$match,PREG_SET_ORDER); if($match && count($match)>0) { foreach($match as $m) { $go=true; $i=0; $getresult=$m[1]; while($go) { if($i>=20) //最多支持20个标签 防止死循环 { $go=false;break; } $tmp=$this->execFunc($getresult); if($tmp===false) { $go=false;break; } $getresult=$tmp; $i++; } $cnt=preg_replace($this->tag,$getresult,$cnt,1); } } return $cnt; } function clearTag($cnt)//如果语法错误 则要去除冗余的 标记 { $cnt=preg_replace("/<!--if\((.*?)\)-->/s","",$cnt); $cnt=preg_replace("/<!--endif-->/s","",$cnt); return $cnt; } function parse($cnt)//插件必须拥有这个 方法 否则不会执行 插件任何内容 { $list=explode(chr(13),$cnt); $cnt=$this->getIfList($cnt); $cnt=$this->clearTag($cnt); return $cnt; } }?>
这里插件 要注意的是 必须是一个 class 文件 并且 类名 必须遵循 plugin_类名_ 这样的形式 ,转换到模板 就是
<plugin:类名>....</plugin:类名> /// 这里大小写 是很敏感的。插件 必须拥有parse方法 返回 解析后的内容
个人认为的优点:
1、灵活,扩展性好
2、修改核心无障碍。
3、没有老外的那种 一大堆文件和代码的风格,虽说老外写的东西很牛,但是如果开发的是国人的软件 还是用国人的东西比较适合。
缺点不说了,bug肯定有 ,性能没有老外的好,高手会认为是垃圾,和smarty 不是同一个东西,勿喷
欢迎 各位有兴趣的 好朋友 提供更好的 语法插件
以下是一些注意点 :
1、使用上面程序 必须使用phh5 ,必须开启mb_string 必须支持eval
2、主程序是utf-8,因此必须使用utf8编码, 理论上 模板是gb2312也没问题,但是我没测试
3、由于项目还没交付,同时该模板程序还在不断完善和修改,目前是v0.1 ,因此模板主解析程序 我进行了压缩, 后面会放出 带注释版本的 纯原文件。
4.本模板特别适用于 一线开发人员使用(很忙 很没时间的开发人员), 不建议新手使用(新手还是先学好基础为好),不建议高手使用(高手可能会认为此物是垃圾)
测试程序 我放到了我的网盘 里面 http://url.cn/7dKBks (qq的微云)。
如果不能下载 请留下 邮箱