こんにちは。tomita@atuwebです。
先日イオンの沖縄フェアで購入したスイーツ仕立てのじーまーみとうふが大変美味しくて感動しました。


こういったタイプのものでした。
黒糖のシロップにきな粉、、、かなりオススメですよ!


さて、今回Laraveで実装したプロジェクトにphpmdの静的コード解析を導入しました。
その手順などまとめます。

About

今回のゴールは「LaravelプロジェクトにPHPMDを導入し、コードを改善する」です。

環境

  • macOS Sierra
  • PHP 7.0.10

PHPMDとは

PHPMD – PHP Mess Detector
https://phpmd.org/

PHPMDは潜在的なバグからコーディング規約をチェックすることができる静的解析ツールです。
「PHPMDはPHP版のPMDを目指しています」とありますね。

最短ルート

今回、Laraveのcomposer.jsonにphpmdを定義します。

$ vi composer.json

"require-dev": {
    "phpmd/phpmd" : "@stable"
}

composerをinstall or updateしてじっと待ちましょう。

$ composer update

vendor以下にインストールされたphpmdに、そのままアクセスしてしまいます。

$ vendor/phpmd/phpmd/src/bin/phpmd app/ text codesize,controversial,design,naming,unusedcode

app以下のディレクトリを捜査し、結果を標準出力に出力します。
解析結果は、たとえばこのようなメッセージが出力されます。

/vagrant/www/app/Console/Kernel.php:24 Avoid unused parameters such as '$schedule'.

メッセージに従ってコードをうまくリファクタリングしていきましょう。

composerのグローバルにインストールする

phpmdのようなライブラリはどのプロジェクトでも利用できるよう、composer globalでインストールすると良いですね。

$ composer global require phpmd/phpmd:"@stable"

パスも通しておけば完璧です。

$ echo 'export PATH=$HOME/.composer/vendor/bin:$PATH' >> .bash_profile
$ source .bash_profile

arguments

引数を間違えると叱られてしまいます。

$ vendor/phpmd/phpmd/src/bin/phpmd
Mandatory arguments:
1) A php source code filename or directory. Can be a comma-separated string
2) A report format
3) A ruleset filename or a comma-separated string of rulesetfilenames

Available formats: xml, text, html.
Available rulesets: cleancode, codesize, controversial, design, naming, unusedcode.

Optional arguments that may be put after the mandatory arguments:
--minimumpriority: rule priority threshold; rules with lower priority than this will not be used
--reportfile: send report output to a file; default to STDOUT
--suffixes: comma-separated string of valid source code filename extensions, e.g. php,phtml
--exclude: comma-separated string of patterns that are used to ignore directories
--strict: also report those nodes with a @SuppressWarnings annotation
--ignore-violations-on-exit: will exit with a zero code, even if any violations are found

つまり、こうです。

phpmd [解析対象ファイル or ディレクトリ] [レポートのフォーマット] [ルールセット]

ルールセットは以下2つの指定方法があります。
– 1.ルールセットの文字列を列挙
– 2.ルールセットが定義されたファイル

設定をXML化

先ほど実行したコマンドは、実行できるルールセットを全て指定しております。
このルールセットをXMLに定義し、実行時に指定する形にしましょう。

私が取り急ぎ用意したルールセットは以下です。
以下をphpmd_ruleset.xmlという名称で保存します。

<?xml version="1.0"?>
<ruleset
    name="OREORE PHPMD rule set"
    xmlns="http://pmd.sf.net/ruleset/1.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://pmd.sf.net/ruleset/1.0.0 http://pmd.sf.net/ruleset_xml_schema.xsd"
    xsi:noNamespaceSchemaLocation=" http://pmd.sf.net/ruleset_xml_schema.xsd">
<description>
    OREORE PHPMD rule set
</description>
<rule ref="rulesets/codesize.xml" />
<rule ref="rulesets/controversial.xml" />
<rule ref="rulesets/design.xml" />
<rule ref="rulesets/unusedcode.xml" />
<rule ref="rulesets/naming.xml">
    <exclude name="ShortVariable" />
</rule>
</ruleset>

XMLを保存したら、コマンドを次に変えて実行してみましょう。

$ phpmd app/ text phpmd_ruleset.xml

ルールセットのカスタマイズ

PHPMDでは上記のように、デフォルトのルールセットから一部を除外したり、域値を変更することが可能です。

それでは「短すぎる変数名」のルールセットをカスタマイズしてみましょう。


namingを設定すると、デフォルトでは律儀にも$i$idといった変数名にまで警告を出してくれます。
プロジェクトによってはこの「短い変数名」に対する警告だけで何十行の警告になってしまうと思いますから、「短すぎる変数名」はみなさんが真っ先に除外の対象とするようですね。

「短い変数名」の警告を出しているルールセットは、namingのShortVariableです。

ルールを除外する

先にご紹介したXMには、すでにこの「短い変数名」を除外しておりました。
以下excludeの部分です。

<rule ref="rulesets/naming.xml">
    <exclude name="ShortVariable" />
</rule>

これで「短い変数名」に対する警告は一切でなくなります。

域値を変更する

ShortVariableのデフォルトは3です。
例えばこの域値を変更する場合は次のようにします。

<rule ref="rulesets/naming.xml/ShortVariable">
    <priority>1</priority>
    <properties>
        <property name="minimum" value="2" />
    </properties>
</rule>

特定の変数名をチェック対象外とする

ShortVariableについて言えば、域値を変更してもループカウンタが引っかかってしまいますね。
幸い、特定の変数名をチェック対象外とするオプションがあります。

次のように、’$’はつけずに定義します。

<rule ref="rulesets/naming.xml/ShortVariable">
    <properties>
        <property name="exceptions" value="id,i,j,e,fp" />
    </properties>
</rule>

その他のカスタマイズは

まずは公式をご覧ください。

PHPMD – ルールセットのカスタマイズ方法
https://phpmd.org/documentation/creating-a-ruleset.html

PHPMD – ルール一覧
https://phpmd.org/rules/index.html

具体的な設定値、プロパティ名は上記のURLにも掲載されています。
ライブラリの[src/main/resources/rulesets]以下に、各ルールセットの定義ファイルがあり、このXMLを直接チェックしても、理解がすすみそうですね。

警告と対処方法

私が出してしまった警告と、その対処法です。
全ては網羅していません。

codesize/CyclomaticComplexity

警告内容

The method fooMethod() has a Cyclomatic Complexity of 15. The configured cyclomatic complexity threshold is 10.

循環的複雑度(英: Cyclomatic complexity)は15です。
もっとシンプルにした方がいいんじゃないの?

対処法

リファクタリングする。

codesize/NPathComplexity

警告内容

The method fooMethod() has an NPath complexity of 2616. The configured NPath complexity threshold is 200.

このメソッドのNPathは2616もあるけど、複雑すぎじゃない?
もっとシンプルにできないの?

対処法

リファクタリングする。

NPathとは「ある関数の中の経路数」です。
条件が複雑なif文を書くとあっという間に値が跳ね上がりますよ。

codesize/TooManyMethods

警告内容

The class FooController has 28 non-getter- and setter-methods. Consider refactoring FooController to keep number of methods under 25.

このクラスのメソッド数が多すぎるから、メソッド数を25未満に減らしなよ。

対処方法

クラスを分割する

codesize/TooManyPublicMethods

警告内容

The class FooController has 19 public methods. Consider refactoring FooController to keep number of public methods under 10.

このクラスのパブリックメソッドが多すぎるから、10未満に減しなよ。

対処方法

クラスを分割する

codesize/CyclomaticComplexity

警告内容

The class FooController has an overall complexity of 75 which is very high. The configured complexity threshold is 50.

このクラスの複雑度は75だよ。
一般的なクラスの複雑度はせいぜい50だよ。
ワケがわからなくなるから、このくらいに減らしなよ。

対処方法

メソッド分割する。

codesize/ExcessiveParameterList

警告内容

The method updateFoo() has 12 parameters. Consider reducing the number of parameters to less than 10.

引数が多くない?

対処方法

引数をオブジェクトにまとめる、など。
メソッドの分割が有効なことも。

design/CouplingBetweenObjects

警告内容

The class FooController has a coupling between objects value of 18. Consider to reduce the number of dependencies under 13.

このクラスは18ものオブジェクトと結合しているよ。
依存性が高すぎるよ。
結合しているオブジェクトを13以下に減らしていこうよ。

対処方法

クラスを分割する

naming/ShortVariable

警告内容

Avoid variables with short names like $id. Configured minimum length is 3.

$idなんていう短い変数名は意図が伝わらないから使うべきじゃないよ。

対処方法

変数名を変更する

naming/LongVariable

警告内容

Avoid excessively long variable names like $userLeaderCardFirstAbility. Keep variable name length under 20.

変数名が長すぎるよ。
これは読む気になれないよ。

対処方法

変数名を短くする。
例えば、不要な単語を投げ捨てる。

unusedcode/UnusedFormalParameter

警告内容

Avoid unused parameters such as '$request'.

使っていない引数があるけど、それいるの?

対処方法

引数を変数を削除する。

unusedcode/UnusedLocalVariable

警告内容

Avoid unused local variables such as '$user'.

使っていないローカル変数があるけど、いらないよね?

対処方法

ローカル変数を削除する

例えば、次のように変数宣言と代入を同時におこなった場合に$isIconに警告がでました。

$file = new File($params, $isIcon=true); // Avoid unused local variables such as $isIcon

またforeachで、次のようにループないでkeyもしくはvalueを参照していなかった場合も警告が出ました。

foreach ($array as $key => $value) {
   echo $key;  // Avoid unused local variables such as $value
}

unusedcode/UnusedPrivateMethod

警告内容

Avoid unused private methods such as 'convertContent'.

呼び出されないかわいそうなプライベートメソッドがあるよ。

対処方法

呼び出されないprivateなメソッドを削除する。

警告の対策が難しい場合

フレームワーク実装上の制約によって、PHPMDの警告に対処することが難しいケースがあります。

例えば、Laraveのカスタムバリデートを実装する場合は次のようなコードを書くことになります。

class CustomValidator extends \Illuminate\Validation\Validator
{
    public function validateFoo($attribute, $value, $parameters)
    {
        return strlen($value) > 0;
    }
}

上記では引数が決まっており、カットすると動かなくなってしまいます。

このようなケースに対処するためにはコメントに@SuppressWarningsを定義します。

/**
 * @SuppressWarnings(PHPMD.UnusedFormalParameter)
 */

[UnusedFormalParameter]に相当する文字列は、前述のルール一覧の文字列に相当します。

PHPMD – Rules
https://phpmd.org/rules/index.html

おわりに

人力だけではなく、こう言ったツールを活用して良いコードを書く仕組みを作ってしまいましょう。

下手ですけれども、リファクタリングには次の書籍が活躍してくれますよ。

参考

PHPの静的コード解析ツール『PHPMD』を使ってみた。
http://qiita.com/yuji0602/items/28b0c2363bae8fce055a

composer global
http://qiita.com/ngyuki/items/c785a898343921e99e16

スポンサーリンク
ad_336
ad_336
  • このエントリーをはてなブックマークに追加
  • Evernoteに保存Evernoteに保存