使用PHP-Parser產生AST抽象文法樹,php-parserast

來源:互聯網
上載者:User

使用PHP-Parser產生AST抽象文法樹,php-parserast

0、前言

最近項目的流程逐漸清晰,但是很多關鍵性的技術沒有掌握,也只能一步一步摸索。

由於要做基於資料流分析的靜態程式碼分析,所以前端的工作如:詞法分析、文法分析必不可少。Yacc和Lex什麼的就不再考慮了,查了一天的資料,發現兩款比較適合,一款是Java下的ANTLR,另一款是專門做PHP AST產生的PHP-Parser。

ANTLR是編譯原理領域比較著名的工具了,相對於Yacc和Lex,更加實用。但是對PHP的文法檔案只有一個,折騰了半天才產生調通,發現不太適合,對於”$a=1”產生tokens竟然是[$,a,=,1],無法識別assignment,做得過於粗糙,令人無比失望。

相比之下,PHP-Parser更加專業一些,畢竟專註PHP的詞法、文法分析工作。

 

1、介紹

PHP-Parser的項目首頁是https://github.com/nikic/PHP-Parser。可以對多版本的PHP進行完美解析,產生一顆抽象文法樹。

對於詞法分析,PHP有個內建函數token_get_all()可以用來擷取TOKENS,作為文法分析的輸入,這個開源項目也是用的token_get_all()產生的token流。

 

2、安裝

安裝也很簡單,這裡我是使用的PHP中的包管理工具composer添加的,在項目目錄中執行以下命令即可:

php composer.phar require nikic/php-parser

如果沒有下載Composer,應該先執行下面的命令:

Curl -s http://getcomposer.org/installer | php  

 

3、產生AST

使用composer添加php-parser之後,就可以方便使用。

首先介紹一下PHP-Parser中定義的一些節點類型:

(1)PhpParser\Node\Stmt是語句節點,不帶任何返回資訊(return)的結構,如賦值語句”$a = $b” ;

(2)PhpParser\Node\Expr是運算式節點,可以返回一個值的語言結構,如$var和func()。

(3)PhpParser\Node\Scalar是常量節點,可以用來表示任何常量值。如’string’,0,以及常量運算式。

(4)還有一些節點沒有包括進去,如參數節點(PhpParser\Node\Arg)。

一些節點類的名稱使用了底線,這是為了避免和PHP關鍵字衝突。

PHP-parser的HelloWorld程式如下,該程式碼片段會產生AST:

輸出結果為:


<span style="font-size:12px;">Array(    [0] => PhpParser\Node\Stmt\Echo_ Object    (            [subNodes:protected] => Array                (                    [exprs] => Array                        (                            [0] => PhpParser\Node\Scalar\String Object                                (                                    [subNodes:protected] => Array                                        (                                            [value] => 1+2                                        )                                    [attributes:protected] => Array                                        (                                            [startLine] => 1                                            [endLine] => 1                                        )                                )                            [1] => PhpParser\Node\Scalar\String Object                                (                                    [subNodes:protected] => Array                                        (                                            [value] => chongrui                                        )                                    [attributes:protected] => Array                                        (                                            [startLine] => 1                                            [endLine] => 1                                        )                                )                        )                )            [attributes:protected] => Array                (                    [startLine] => 1                    [endLine] => 1                )        ))</span>

可以看到,這課AST只有一個節點Echo_,此節點有一個子節點exprs,可以使用$stmts[0]->exprs進行訪問。

對於節點中的attributes資訊是用來儲存startLine和endLine以及comments的。可以使用getAttributes(),getAttribute(‘startLine’),setAttribute(),hasAttribute()方法進行訪問。

開始行號startLine可以通過getLine()/setLine()方法進行訪問(也可以getAttribute(‘startLine’))。注釋資訊可以使用getDocComment()擷取。

訪問節點上的值:如訪問值“chongrui”,使用$stmts[0]->exprs[1]->value;即可。

 

 

4、節點遍曆

對抽象文法樹的遍曆非常方便,使用PhpParser\NodeTraverser類即可。同時,支援自訂的Visitor對象。因為在實際應用中,對PHP源碼進行分析,往往是不知道AST的具體結構,這時需要動態去判斷每個節點的類型資訊。

這些判斷統一寫到MyNodeVisitor中,該類繼承了一個父類NodeVisitorAbstract,這個類中有一些方法:

(1)beforeTraverse()方法用於遍曆之前,通常用來在遍曆前對值進行重設。

(2)afterTraverse()方法和(1)相同,唯一不同的地方是遍曆之後才觸發。

(3)enterNode()和leaveNode()方法在對每個節點訪問時觸發。

enterNode在進入節點時觸發,比如在訪問節點的子節點之前。這個方法可以返回NodeTraverser::DONT_TRAVERSER_CHILDREN,用來跳過該節點的孩子節點。

leaveNode在遍曆節點完成之後觸發。它可以返回

NodeTraverser::REMOVE_NODE,這種情況下,當前節點會被刪除。如果返回一個節點的集合,那麼這些節點會併入到父節點的array中,比如array(A,B,C),B節點被array(X,Y,Z)替換,變成array(A,X,Y,Z,C) .

下面的程式碼片段對$code進行解析,產生AST,並且在遍曆時,當發現遍曆節點時String類型時,就進行輸出。

結果會輸出1,2。

5、其他AST表示

有時候會將AST進行文本化持久儲存,這個功能PHP-Parser也支援。

(1)簡單的進行序列化

使用serialize()和unserialize()進行序列化和還原序列化操作,可以對AST進行持久儲存。 

(2)易於閱讀的儲存形式

分別是完美列印和XML持久儲存,在這裡不做詳細介紹,有需要的時候可以看項目的文檔:

https://github.com/nikic/PHP-Parser/blob/master/doc/3_Other_node_tree_representations.markdown

 

 

6、總結

至少在PHP靜態分析方面,PHP-Parser在功能方面大大優於ANTLR。如何構建一個PHP自動化審計系統,這個PHP-Parser肯定會發揮不小的作用:)~


聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.