把模板标记转换为PHP代码函数CompilerAll()
实际上这个函数没有做什么,完全就是调用别人的东西,真正把模板标记变成转成php的是函数CompilerOneTag(&$cTag),这个编译单个标记函数才是真正的发挥作用的,就像一个公司一样,真正为公司出大力的是一线的工作人员,函数CompilerAll()只是这个公司的一管理层而已,它只是把别人的成果拿来使用。
但是,没有这个函数也中不行,它其实也做了一点事就是把每个标记编译好的结果重新组装起来,放在$this->sourceString里面,也就是我们在/data/tplcache/里面的.inc文件的内容。
这个函数所在的文件:/include/dedtemplate.class.php
代码分析:
这个编译函数最重要的一段代码是:
$nextTagEnd = 0; for($i=0; isset($this->cTags[$i]); $i++) { $ResultString .= substr($this->sourceString, $nextTagEnd, $this->cTags[$i]->startPos - $nextTagEnd); $ResultString .= $this->CompilerOneTag($this->cTags[$i]); $nextTagEnd = $this->cTags[$i]->endPos; }
在分析这段代码前,我先把其中一个的标记$this->cTags 打印出来供我们分析代码参考使用。
Tag Object ( [isCompiler] => [tagName] => global [innerText] => [startPos] => 1193 [endPos] => 1211 [cAtt] => TagAttribute Object ( [count] => 0 [items] => Array ( [tagname] => global [name] => cid ) ) [tagValue] => [tagID] => 1 )
在这个tag对象里面,这个函数用到了对象里面的
[startPos] => 1193
[endPos] => 1211
代码:substr($this->sourceString, $nextTagEnd, $this->cTags[$i]->startPos - $nextTagEnd)
实际意思就是:在模板字符串中,从零开始(因为$nextTagEnd初始值为0)查找,一直找到标记开始的地方,把这些代码放到字符串$ResultString里面。
举例说明:
上面这行代码substr($this->sourceString, $nextTagEnd, $this->cTags[$i]->startPos - $nextTagEnd)意思是:在下图中的代码里查找标签。
若找到,例如找到{dede:var.name/},则把这个标签前面的代码,也就是绿色方框内的字符串放到$ResultString里面。
然后,通过$ResultString .= $this->CompilerOneTag($this->cTags[$i]);这行代码,去把找到的{dede:var.name/}这个标签解析成php代码,返回回来,加到上图中,标签{dede:var.name/}当然,是也是通过这行代码实现的。
找到标签的结束位置也就是{dede:var.name/}后面的位置值,即我们上面提供的tag对象里面的[endPos]=>1211。这样下次遍历标签后,就从1211位置开始,也就是上图中的的蓝色框,这样往复循环,直接把整个模板遍历完后,这样就把模板中的所有的标签解析成了php代码。
但是此时有一个问题,就是一般的模板并不是以标签结尾的,也就是说最后一个标签后面还有html或其它代码,这时如果不处理的话,可能就会丢掉最后一个标签后面的代码,这样模板就不完整了。
所以,我们也要把最后一个标签后面的代码加到$ResultString后面,这样才是完整的模板。
代码:
$slen = strlen($this->sourceString); if($slen > $nextTagEnd) { //取模板字符串里面的下一个标记,即$nextTagEnd下面的部分 $ResultString .= substr($this->sourceString,$nextTagEnd,$slen-$nextTagEnd); }
判断一下模板字符串长度是不是比从模板开头到最后一个标签结束的长度要长?若成立,说明,$ResultString里面存放的是最后一个标签以前的字符串,并不包括标签以后的。
例如上图中{dede:global.cid/}标签是最后一个标签,但是在这个标签后面还有:
';" value='文章回收站' /> </td> </tr> </table> </td> </tr> </table>
这些字符串,所以,我们通过substr($this->sourceString,$nextTagEnd,$slen-$nextTagEnd)这个函数,来截取这最后一段字符串加到$ResultString里面,这时的$ResultString已经是一个完整的模板字符串了。
这样整个模板就替换完毕。
把这个替换后的字符串,放到$this->sourceString里面,即$this->sourceString = $ResultString;
然后,调用模板解析函数:$this->ParseTemplate()
实验:
在网站根目录里面建立一个模板文件index.htm,文件内容如下:
<font color="Blue">{dede:datalist}</font> <tr align='center' bgcolor="#FFFFFF" height="26" align="center" onMouseMove="javascript:this.bgColor='#FCFDEE';" onMouseOut="javascript:this.bgColor='#FFFFFF';"> <td nowrap> <font color="Blue">{dede:field.id/}</font> </td> <td> <input name="arcID" type="checkbox" id="arcID" value="<font color="Blue">{dede:field.id/}</font>" class="np" /> </td> <td><font color="Blue">{dede:field.senddate function='GetDateMk(@me)'/}</font></td> <td><a href='content_list.php?cid=<font color="Blue">{dede:field.typeid/}</font>'><font color="Blue">{dede:field.typeid function='GetTypename(@me)'/}</font></a></td> <td> <img src='images/trun.gif' title="编辑属性" alt="编辑属性" onClick="QuickEdit({dede:field.id/}, event, this);" style='cursor:pointer' border='0' width='16' height='16' /> <img src='images/gtk-edit.png' title="编辑" alt="编辑" onClick="editArc(<font color="Blue">{dede:field.id/}</font>);" style='cursor:pointer' border='0' width='16' height='16' /> <img src='images/part-list.gif' title="预览" alt="预览" onClick="viewArc(<font color="Blue">{dede:field.id/}</font>);" style='cursor:pointer' border='0' width='16' height='16' /> </td> </tr> <font color="Red">{/dede:datalist} {dede:if $adminid==$mid }</font> <input type='button' class="coolbg np" onClick="location='content_list.php?cid=<font color="Blue">{dede:global.cid/}</font>&mid=0';" value='全部文档' /> {else} <input type='button' class="coolbg np" onClick="location='content_list.php?cid=<font color="Blue">{dede:global.cid/}</font>&mid=<?php echo $cuserLogin->getUserID(); ?>';" value='我的文档' /> {/dede:if} <font color="Blue">{dede:global.CheckUserSend/}</font> 复制代码
建立一个test.php文件代码如下所示:
<?php require_once('./include/common.inc.php'); require_once ('./include/dedetemplate.class.php'); $tpl=new DedeTemplate(); $tpl->LoadTemplate('index.htm'); // $tpl->display(); include $tpl->CacheFile(); ?>
注意:一般情况下不建议使用$tpl->display();而是使用include $tpl->CacheFile();为什么?因为使用$tpl->display()的时候要重新解压一次$GLOBALS变量,所以在动态页中,应该尽量少用本方法。
我们执行一下test.php文件看看能不能正常解析这个index.htm模板文件。在浏览器上面输入localhost/test.php,这时在data/tplcache/文件夹下面生成了一个缓存文件index_fd491768bbe8b2f208d6e5d8.inc.打开这个文件
我们看到了如下代码:
<?php <font color="Blue"> if(!isset($GLOBALS['_vars'])) $GLOBALS['_vars'] = array(); $fields = array(); //织梦基地:www.dedebase.com $atts = array(); $atts['tagname'] = 'datalist'; $blockValue = $this->refObj->GetArcList($atts,$this->refObj,$fields); if(is_array($blockValue)){ foreach( $blockValue as $key=>$fields ) { ?></font> <tr align='center' bgcolor="#FFFFFF" height="26" align="center" onMouseMove="javascript:this.bgColor='#FCFDEE';" onMouseOut="javascript:this.bgColor='#FFFFFF';"> <td nowrap> <?php echo $fields['id']; ?> </td> <td> <input name="arcID" type="checkbox" id="arcID" value="<font color="Blue"><?php echo $fields['id']; ?></font>" class="np" /> </td> <td><?php echo GetDateMk($fields['senddate']); ?></td> <td><a href='content_list.php?cid=<?php echo $fields['typeid']; ?>'><font color="Blue"><?php echo GetTypename($fields['typeid']); ?></font></a></td> <td> <img src='images/trun.gif' title="编辑属性" alt="编辑属性" onClick="QuickEdit(<font color="Blue"><?php echo $fields['id']; ?></font>, event, this);" style='cursor:pointer' border='0' width='16' height='16' /> <img src='images/gtk-edit.png' title="编辑" alt="编辑" onClick="editArc(<font color="Blue"><?php echo $fields['id']; ?></font>);" style='cursor:pointer' border='0' width='16' height='16' /> <img src='images/part-list.gif' title="预览" alt="预览" onClick="viewArc(<font color="Blue"><?php echo $fields['id']; ?></font>);" style='cursor:pointer' border='0' width='16' height='16' /> </td> </tr> <font color="Red"><?php } } if($adminid==$mid){ ?></font> <input type='button' class="coolbg np" onClick="location='content_list.php?cid=<font color="Blue"><?php echo $GLOBALS['cid']; ?></font>&mid=0';" value='全部文档' /> <font color="Red"><?php } else{ ?></font> <input type='button' class="coolbg np" onClick="location='content_list.php?cid=<font color="Blue"><?php echo $GLOBALS['cid']; ?></font>&mid=<font color="Blue"><?php echo $cuserLogin->getUserID(); ?></font>';" value='我的文档' /> <font color="Blue"><?php } echo $GLOBALS['CheckUserSend']; ?></font>
看里面的几个标签全部正常解析过来了。