phpmdでコード解析＋チェックルールのカスタマイズしてみる

phpcsに続きコーディングの品質向上のためphpmdを使うようにしてみました。

[phpmd](https://phpmd.org/download/index.html)

phpmdは潜在的にバグになりそうなコードや改善の余地があるコードなどを検出してくれるツールです


## phpmdインストール

公式通り、`composer.json`に下記を追記してcomposer installします

```
{
    "require-dev": {
        "phpmd/phpmd" : "*"
    }
}
```

## 使い方

コマンドラインで実行する際は下記のように実行できます。
`phpmd /path/to/file xml codesize,naming,cleancode`

xml以後のオプションで検出ルールを指定します。
ルールが設定してあるxmlは`vendor/phpmd/phpmd/src/main/resources/rulesets/`以下にあります。

デフォルトでは下記があります。

* cleancode.xml
* codesize.xml
* controversial.xml
* design.xml
* naming.xml
* unusedcode.xml

またそれぞれのルールの実装は`vendor/phpmd/phpmd/src/main/php/PHPMD/Rule/`にあります。

なので、ルールのカスタマイズするには、新規にruleを定義したxmlを作成して、それに対するチェックの実装を行っていく感じになります。


## カスタマイズルールを作ってみる

今回はtypoチェックを実装してみました。

まずカスタマイズルール用にxmlを作ります。

```
vi vendor/phpmd/phpmd/src/main/resources/rulesets/myStandard.xml


<?xml version="1.0"?>

<ruleset name="My Standard Rules">

    <description>
This ruleset contains a my standard rules.
    </description>

    <rule name="CheckTypo"
          since="0.2"
          message = "Maybe typo. {0} : {1} -> {2}"
          class="PHPMD\Rule\MyStandard\CheckTypo"
          externalInfoUrl="#">
        <description>
            <![CDATA[
Maybe typo.
            ]]>
        </description>
        <priority>1</priority>
        <properties />
        <example>
            <![CDATA[
protocal->protocol
recompence->recompense
            ]]>
        </example>
    </rule>
</ruleset>

```

上記のように定義して、`PHPMD\Rule\MyStandard\CheckTypo`にチェックルールの実装を行っていきます。

typo例はこちらのものを参考としました。

[Lists_of_common_misspellings](https://en.wikipedia.org/wiki/Wikipedia:Lists_of_common_misspellings/For_machines)



既存の実装を元に下記のように実装してみました。
`./resources/typoList.csv`にtypo単語リストを置いています


```
vendor/phpmd/phpmd/src/main/php/PHPMD/Rule/MyStandard/CheckTypo.php


namespace PHPMD\Rule\MyStandard;

use PHPMD\AbstractNode;
use PHPMD\AbstractRule;
use PHPMD\Rule\FunctionAware;
use PHPMD\Rule\MethodAware;

/**
 * This rule CheckTypo.
 * typo check
 *
 */
class CheckTypo extends AbstractRule implements MethodAware, FunctionAware
{

    private static $typoList = [];

    /**
     * This method checks typo
     *
     * @param \PHPMD\AbstractNode $node
     * @return void
     */
    public function apply(AbstractNode $node)
    {
        $typoList = $this->getTypoList();

        foreach ($node->findChildrenOfType('Variable') as $variable) {
            $image = $variable->getImage();
            foreach ($typoList as $key => $value) {
                if (preg_match("/$key/", $image)) {
                    $this->addViolation($variable, array($image, $key, $value));
                    break;
                }
            }
        }
    }

    /**
     * get typoList
     * @return void
     */
    public function getTypoList()
    {
        if (self::$typoList) {
            return self::$typoList;
        }
        $typoList = [];
        $fp = fopen(dirname(__FILE__) . "/resources/typoList.csv", "r");
        while (!feof($fp)) {
                $tmpArr = fgetcsv($fp);
                $typoList[$tmpArr[0]] = $tmpArr[1];
        }
        self::$typoList = $typoList;
        fclose($fp);

        return self::$typoList;
    }
}

```

実行はこんな感じで、
`phpmd /path/to/file xml myStandard`


既存の実装を元になんとなくやってみましたが、変数名のtypo検出ができました！

こんな感じでカスタマイズルールを実装することでプロジェクト共通で品質向上やレビューの負荷軽減等していけたらと思いますん。