闇PHP勉強会は前から気になっていたイベントですが、たまたま弊社で開かれることになっていたので、どうにかして発表してみました。
スライドはこちら→https://speakerdeck.com/edvakf/xpathdesosukodojian-suo-1
コード→https://github.com/edvakf/php-ast-to-xml
例えば「in_arrayの第三引数が与えられていない箇所」みたいなのを探したい時に、便利なツールは無いんですよ。
前に会社の人がPHPのASTに対してjQuery風のクエリ言語で検索できるツールを作ってたのですが、そのDSLを覚えるのもなかなか面倒なのです。
PHP7になってASTを作るようになったのですが、これをPHP側から触れるようにするためのphp-astというツールを使って、ASTを機械的にXMLに変換することができます。下のようなXMLの形に落ち着いたのは僕の好みも大きく、ちょっと冗長ではあるのですが、大事なのは機械的に変換できるということです。
$ cat some.php
<?php
in_array(1, [1, 2]);
$ php-ast-to-xml some.php
<?xml version="1.0"?>
<ast>
<AST_STMT_LIST lineno="1">
<AST_CALL lineno="3">
<expr>
<AST_NAME lineno="3" NAME_NOT_FQ="NAME_NOT_FQ">
<name>
<scalar value="in_array" type="string"/>
</name>
</AST_NAME>
</expr>
<args>
<AST_ARG_LIST lineno="3">
<scalar value="1" type="int"/>
<AST_ARRAY lineno="3">
<AST_ARRAY_ELEM lineno="3">
<value>
<scalar value="1" type="int"/>
</value>
<key/>
</AST_ARRAY_ELEM>
<AST_ARRAY_ELEM lineno="3">
<value>
<scalar value="2" type="int"/>
</value>
<key/>
</AST_ARRAY_ELEM>
</AST_ARRAY>
</AST_ARG_LIST>
</args>
</AST_CALL>
</AST_STMT_LIST>
</ast>
すると、このXMLに対してクエリを書くことができて、「in_arrayの第三引数が与えられていない箇所」の場合はこうなります。
$ php-ast-xpath some.php '//AST_CALL[./expr/AST_NAME/name/scalar[@value="in_array"] and not(./args/AST_ARG_LIST/*[3])]'
some.php:3
最後に「妄想」として書いている、ASTからPHPのソースコードに復元することができれば…というところは、JavaScript界隈では数年前からそういうことが行われているので、不可能ではないはずです。
GoogleではClangのASTを使ってC++をリファクタリングしているそうです。