PHP

XPathでソースコード検索する話 @ 第七回闇PHP勉強会

闇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++をリファクタリングしているそうです。

https://www.youtube.com/watch?v=mVbDzTM21BQ