打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
怎么一步步编写简单的PHP的Framework(二十四)

怎么一步步编写简单的PHP的Framework(二十四)

发表于2年前(2012-12-30 15:00)   阅读(584) | 评论(4 7人收藏此文章, 我要收藏
3

    首先taglib需要读取某一个文件,具体的代码如下:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public function parse($file) {
        $htmlContents = file_get_contents($file);
        //此处本来可以使用$dom->loadHTMLFile($file)来完成
        //但是因为xml格式较为严格,所以此处使用xml来解析
        $xmlContents = '<?xml version="1.0" encoding="utf-8"?><root>'.$htmlContents.'</root>';
        file_put_contents($file,$xmlContents);
        //将即将处理的文件变为xml文件
        try {
            $this->_dom = new DOMDocument();
            $this->_dom->load($file);
            $contents = $this->_parseTag($this->_dom->documentElement);
            return $contents;
        } catch(DOMException $e) {
            echo $e->getMessage();
        }
    }
   处理过程为:首先为这个HTML文件添加XML的头:<?xml version = "1.0" encoding = "utf-8" ?>


   由于XML需要一个根节点,所以我们使用了<root></root>。

   注意,这个地方的$file是一个路径,它是已经经过ViewChecker处理的文件,并不是通过display()调用得到的这个文件了。

   这个函数只是将整个HTML代码构建成为一个DOM树,这个树的具体处理过程交给了_parseTag这个protected的方法处理。

   好,我们再看看_parseTag的代码:

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
protected function _parseTag($element) {
        $contents = "";
        if($element->hasChildNodes()) {
            foreach($element->childNodes as $childNode) {
                if(XML_TEXT_NODE === $childNode->nodeType) {
                    if('' !== trim($childNode->nodeValue)) {
                        //文本节点
                        return $childNode->nodeValue;
                    }
                } else {
                    $tagName = $childNode->nodeName;
                    $tagAttr = array();
                    if($childNode->hasAttributes()) {
                        //抓取这个节点的所有属性
                        foreach($childNode->attributes as $attr) {
                            $tagAttr[$attr->nodeName] = $attr->nodeValue;
                        }
                    }
                    $contents .= $this->_parseTagStart($tagName,$tagAttr);
                    $contents .= $this->_parseTag($childNode);
                    $contents .= $this->_parseTagEnd($tagName);
                }
            }
        } else {
            //文本节点
            return $element->nodeValue;
        }
        return $contents;
    }


     由于视图文件只是第一次解析的时候才会经过如此复杂的处理,如果后面没有改动,第二次调用的会是已经被解析的内容,所以这个地方我没有过多的考虑效率。

     这个函数实际上就是将标签一个个的取出来,标签名为$tagName,标签的所有属性为$tagAttr,然后传递给$this->_parseTagStart和$this->_parseTag,$this->_parseTagEnd即可。

     为什么在_parseTagStart和_parseTagEnd中间会有一个_parseTag呢,这是为了递归的调用,因为一个标签中间可能会有其他的标签,如:


1
2
3
4
<ul>
   <li></li>
   <li></li>
</ul>


     现在的ul标签中间就有两个li标签。

     那么_parseTagStart处理一个标签的什么内容呢,现在我们以一个具体的标签举例:

    <li id = "li" class = "test"></li>

    那么_parseTagStart会处理<li id = "li" class = "test">,而</li>会交给_parseTagEnd处理。

   这两个函数都会首先判定这个标签是否需要解析,因为除了标签库定义的标签,HTML本身也定义了很多标签,这些标签是不需要处理的,所以我们需要定义一个变量,这个变量存储所有要解析的标签和它们的属性。

    

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
protected $_tags = array(
        'foreach' => array('attr' => 'from|item|key'),
        'if' => array('attr' => 'condition'),
        'elseif' => array('attr' => 'condition'),
        'else' => array('attr' => ''),
        'include' => array('attr' => 'file|type'),
        'print' => array('attr' => 'name|type'),
        'for' => array('attr' => 'start|end|loop'),
        'switch' => array('attr' => 'name'),
        'case' => array('attr' => 'name'),
        'default' => array('attr' => ''),
        'break' => array('attr' => ''),
        'continue' => array('attr' => ''),
        'while' => array('attr' => 'condition|loop|start'),
        'isset' => array('attr' => 'name'),
        'set' => array('attr' => 'name|value'),
        'flash' => array('attr' => 'id|class|value|width|height'),
        'page' => array('attr' => 'currentPage|totalPages|totalRecords|href|isAjax|pageRange')
    );


     好,现在就直接贴出_parseTagStart的代码了:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
protected function _parseTagStart($tagName,$tagAttr = array()) {
        if($this->_isInTagLib($tagName)) {
            $method = '_parse'.(ucfirst($tagName).'Start');
            return $this->$method($tagName,$tagAttr);
            //调用相应的解析函数
        } else {
            //非标签库的标签
            if('#comment' === $tagName) {
                //注释
                $tag = '<!-- ';
            } else {
                $tag = '<'.$tagName;
                foreach($tagAttr as $attr=>$val) {
                    $tag .= ' '.$attr.' = "'.$val.'"';
                }
                if(!$this->_isSpecialHtmlTag($tagName)) {
                    $tag .= '>';
                } else {
                    $tag .= '/>';
                }
            }
            return $tag;
        }
    }
   首先有一个辅助函数_isInTagLib,如果判定结果是在taglib中,那么交给具体的函数来处理,否则不处理。


   对于_parseTagEnd也很类似:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
protected function _parseTagEnd($tagName) {
        if($this->_isInTagLib($tagName)) {
            $method = '_parse'.(ucfirst($tagName).'End');
            if(!method_exists($this,$method)) {
                return $this->_parseUniversalTagEnd($tagName);
            } else {
                return $this->$method($tagName);
            }
        } else {
            //非标签库的标签
            if('#comment' === $tagName) {
                //注释
                return ' -->';
            } else {
                if(!$this->_isSpecialHtmlTag($tagName)) {
                    return '</'.$tagName.'>';
                } else {
                    return '';
                }
            }
        }
    }


     那么现在假设存在一个标签foreach在标签库中,我们只需要定义一个_parseForeachStart和_parseForeachEnd处理即可。

     taglib这个类不会定义完所有的标签,用户需要扩展标签的时候,只需要继承taglib,然后覆盖$_tags即可。

     建议在用户自定义的标签库这个类里面使用$_myTags这个变量存储用户自定义的标签,然后在__construct函数中将$_myTags也加入到$_tags变量中。

      那么现在我直接贴出foreach这个标签的处理函数,首先是_parseForeachStart:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
protected function _parseForeachStart($tagName,$tagAttr = array()) {
        if(!array_key_exists('from',$tagAttr) || !array_key_exists('item',$tagAttr)) {
            $this->_log('foreach标签必须含有from和item两个属性');
            return '';
        }
        if(!$this->_isTagAttrLegal($tagName,$tagAttr)) {
            //如果存在不合法的标签,直接返回空串
            return '';
        }
        $tag = '<?php if(isset('.$tagAttr['from'].')): ';
        $tag .= 'foreach('.$tagAttr['from'].' as ';
        if(array_key_exists('key',$tagAttr)) {
            $tag .= '$'.$tagAttr['key'].'=>';
        }
        $tag .= '$'.$tagAttr['item'].'): ?>';
        return $tag;
    }
      然后是_parseForeachEnd:


  

1
2
3
4
protected function _parseForeachEnd($tagName) {
        $tag = '<?php endforeach; endif; ?>';
        return $tag;
    }


     好吧,视图这一块儿就说完了。

     给大家说声不好意思啊,的确视图这一块儿说得太匆忙了,而且不具体,的确是因为最近没有时间了,马上就要回去了,回去之后没有网了,我不想等到下学期再写,下学期我再将这些内容更细致的讲解一下了。

     那这学期就说这么多了,这个系列就下学期再更新了,祝大家新年快乐!

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
ThinkPHP标签制作教程
PHP数组的定义取值以及遍历方法
每日学习心得:UEditor样式被过滤无法显示问题
从URL到页面
解析Html生成标签树
web2.0中的tag及其技术实现
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服