0. はじめに
最近、プロジェクトのプロセスが徐々に明らかになってきましたが、多くの主要なテクノロジーは習得されておらず、段階的に探求することしかできません。
データフロー分析に基づいた静的コード分析のため、字句解析や構文解析などのフロントエンド作業が必須となります。 Yacc と Lex は考慮されなくなりました。1 日情報を確認した結果、1 つは Java の ANTLR で、もう 1 つは PHP AST 生成に特化した PHP-Parser がより適していることがわかりました。
ANTLR は、Yacc や Lex と比較して、コンパイル原理の分野でよく知られたツールです。しかし、PHP の構文ファイルは 1 つしかなく、生成と調整に長い間苦労した結果、「$a=1」に対して生成されたトークンは [$,a, =,1] と、課題が認識できませんでした。
それに比べて、PHP-Parser は PHP の字句解析と文法解析に重点を置いています。
1. はじめに
PHP-Parser プロジェクトのホームページは https://github.com/nikic/PHP-Parser です。複数のバージョンの PHP を完全に解析し、抽象構文ツリーを生成できます。
字句解析のために、PHP には、構文解析の入力として TOKEN を取得するために使用できる組み込み関数 token_get_all() が含まれています。このオープン ソース プロジェクトは、token_get_all() によって生成されたトークン ストリームも使用します。
2. インストール
ここでは、PHP のパッケージ管理ツールである Composer を使用して、プロジェクト ディレクトリで次のコマンドを実行するだけでインストールできます。 parser
Composer をダウンロードしていない場合は、まず次のコマンドを実行する必要があります:
Curl -s http://getcomposer.org/installer php
3. Composer を使用して php を追加した後、AST
を生成します。 -parser、便利に使えます。
最初に、PHP パーサーで定義されているいくつかのノード タイプを紹介します。
(1) PhpParserNodeStmt はステートメント ノードであり、代入ステートメント "$a = $b";
( 2 など) の戻り情報 (return) を持たない構造です。 ) PhpParserNodeExpr は、$var や func() などの値言語構造を返すことができる式ノードです。
(3) PhpParserNodeScalar は定数ノードであり、任意の定数値を表すために使用できます。 「文字列」、0、定数式など。
(4) パラメータノード(PhpParserNodeArg)など、含まれていないノードがあります。
一部のノード クラス名は、PHP キーワードとの競合を避けるためにアンダースコアを使用します。
PHP パーサーの 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_ というノードが 1 つだけあります。このノードには子ノード expr があり、$stmts[0]->exprs を使用してアクセスできます。
ノード内の属性情報は、startLine、endLine、およびコメントを格納するために使用されます。 getAttributes()、getAttribute(‘startLine’)、setAttribute()、hasAttribute() メソッドを使用してアクセスできます。
開始行番号 startLine には、getLine()/setLine() メソッドを通じてアクセスできます (getAttribute(‘startLine’) を使用することもできます)。コメント情報はgetDocComment()で取得できます。
ノード上の値にアクセスする: たとえば、値「chongrui」にアクセスするには、$stmts[0]->exprs[1]->value; を使用します。
4. ノードのトラバーサル
抽象構文ツリーをトラバースするには、PhpParserNodeTraverser クラスを使用するだけで非常に便利です。同時に、カスタマイズされた Visitor オブジェクトもサポートされます。実際のアプリケーションでは、PHP のソースコードを解析する際に、AST の具体的な構造が不明な場合が多いため、この場合、各ノードの型情報を動的に決定する必要があります。これらの判断は MyNodeVisitor に一律に書き込まれます。このクラスは親クラス NodeVisitorAbstract を継承します。
(1) beforeTraverse() メソッドはトラバーサルの前に使用され、通常は前の値を比較するために使用されます。トラバーサル リセットを実行します。
(2) afterTraverse() メソッドは (1) と同じですが、唯一の違いは、トラバース後にトリガーされることです。
(3) 各ノードがアクセスされると、enterNode() メソッドと LeaveNode() メソッドがトリガーされます。
enterNode は、ノードの子ノードにアクセスする前など、ノードに入るときにトリガーされます。このメソッドは、このノードの子ノードをスキップするために使用される NodeTraverser::DONT_TRAVERSER_CHILDREN を返すことができます。
leaveNode は、ノードのトラバーサルが完了した後にトリガーされます。
NodeTraverser::REMOVE_NODE を返すことができ、その場合、現在のノードが削除されます。ノードのコレクションが返された場合、これらのノードは親ノードの配列 (array(A,B,C) など) にマージされ、B ノードは array(X,Y,Z) に置き換えられ、配列になります。 (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 パーサーは間違いなく大きな役割を果たします:)~