PHP Mess Detector (phpmd)の警告の一覧

phpmdとは

PHPMD - PHP Mess Detector
phpmd/phpmd - Packagist
PHPMD is a spin-off project of PHP Depend and aims to be a PHP equivalent of the well known Java tool PMD.

PHPコードの静的解析ツールです。バッドプラクティスな箇所を指摘してくれます。どこからリファクタリングすればいいかの目安にもなります。

ソースを書いた人も、レビューする人にも便利なツールです。

古くは、2012年に1.4.0で。php: >= 5.3.0。

最新は、2020-09-23に、2.9.1。php: >= 5.3.9。

インストール

composerでインストールします。

$ composer require --dev phpmd/phpmdCode language: Bash (bash)

使い方

使い方は、ファイルやディレクトリをカンマ区切りで指定します。ワイルドカードは指定できません。

$ ./vendor/bin/phpmd app/a.php           text cleancode,codesize,controversial,design,naming,unusedcodeCode language: Bash (bash)

複数ファイルを指定する場合は、カンマ区切りでファイルを並べます。

$ ./vendor/bin/phpmd app/a.php,app/b.php text cleancode,codesize,controversial,design,naming,unusedcodeCode language: Bash (bash)

ディレクトリも指定できます。

$ ./vendor/bin/phpmd app  text cleancode,codesize,controversial,design,naming,unusedcodeCode language: Bash (bash)

app下のvendor、tmpを除外したい場合は

$ ./vendor/bin/phpmd app  text cleancode,codesize,controversial,design,naming,unusedcode  --exclude "*/vendor/*,*/tmp/*"Code language: Bash (bash)

composer.jsonに登録しておきます。

  "scripts": {
    "phpmd": [
      "./vendor/bin/phpmd app  text cleancode,codesize,controversial,design,naming,unusedcode  --exclude \"*/vendor/*,*/tmp/*\"",
    ]
  }
Code language: JSON / JSON with Comments (json)

composer phpmd で全対象ファイルをphpmdにかけます。

$ composer phpmdCode language: JSON / JSON with Comments (json)

ファイル1つをphpmdしたいとき、長いコマンドを打つのは面倒なので、シェルスクリプト ./bin/phpmd.sh を作っておきます。

#!/bin/sh -eu
./vendor/bin/phpmd $1 text cleancode,codesize,controversial,design,naming,unusedcodeCode language: Bash (bash)

chmod +x しておきます。

$ chmod +x bin/phpmd.sh

$ ./bin/phpmd.sh  app/a.php
Code language: Bash (bash)

ルールのカスタマイズ

How to create a custom rule set

プロジェクトの全ファイルで、ElseExpressionやCamelCaseXXXを抑制したい場合は、カスタムルールxmlを作成します。

カスタムルールxmlの例

<?xml version="1.0"?>
<ruleset name="My first 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>
        My custom rule set that checks my code...
    </description>

    <rule ref="rulesets/cleancode.xml">
        <exclude name="ElseExpression" />
        <exclude name="StaticAccess" />
        <exclude name="MissingImport" />
    </rule>

    <rule ref="rulesets/codesize.xml">
        <exclude name="TooManyPublicMethods" />
    </rule>

    <rule ref="rulesets/controversial.xml">
        <exclude name="CamelCaseClassName" />
        <exclude name="CamelCasePropertyName" />
        <exclude name="CamelCaseMethodName" />
        <exclude name="CamelCaseParameterName" />
        <exclude name="CamelCaseVariableName" />
    </rule>

    <rule ref="rulesets/design.xml">
        <exclude name="NumberOfChildren" />
    </rule>

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

    <rule ref="rulesets/unusedcode.xml">
        <exclude name="UnusedLocalVariable" />
        <exclude name="UnusedFormalParameter" />
    </rule>
</ruleset>Code language: HTML, XML (xml)

このようなxmlを作っておきます。ファイル名は任意ですが、phpmd.xml、phpmd_myproject.xml、myproject_phpmd.xmlのようにしておくとわかりやすいです。

phpmdコマンドのcleancode,codesizeなどを指定する箇所で、カスタムxmlを指定します。

$ ./vendor/bin/phpmd  src  text  ./phpmd.xmlCode language: Bash (bash)

シェルスクリプトを作るなら、

#!/bin/bash -eu

cwd=$(dirname $0)
$cwd/../vendor/bin/phpmd  $1  text  $cwd/../phpmd.xmlCode language: Bash (bash)

警告の一覧

cleancode

@SuppressWarningsメッセージ例
PHPMD.BooleanArgumentFlagThe method bar has a boolean flag argument $flag, which is a certain sign of a Single Responsibility

引数のbool変数でロジックを振り分けているなら、2つのメソッドに分けよう。
PHPMD.ElseExpressionThe method bar uses an else expression. Else clauses are basically not necessary and you can simplify the code by not using them.

(ヌルチェック、値の範囲チェックなど、前処理のifは)elseを使わず、アーリーリターンしよう。
PHPMD.IfStatementAssignmentAvoid assigning values to variables in if clauses and the like (line '8', column '13')

【重要】if条件内で代入禁止。==のタイプミス?
PHPMD.StaticAccessAvoid using static access to class 'Bar' in method 'bar'.

クラス名::staticメソッドのアクセス禁止
PHPMD.DuplicatedArrayKeyDuplicated array key xxx, first declared at line 8.

【重要】配列で同じキーが登録されているよ。(一つめの値は、2つめの値で上書きされる)
PHPMD.ErrorControlOperatorRemove error control operator '@' on line 8.

エラー抑制子@を削除しよう。
PHPMD.MissingImportMissing class import via use statement (line '8', column '13').

(classに対応した)useをしていないよ。
PHPMD.UndefinedVariableAvoid using undefined variables such as '$xxx' which will lead to PHP notices.

【重要】値が未設定の変数は禁止。

if条件内の代入防止のため、
if ('hoge' == $s)
のように左右逆に書く人もいるわ

codesize【重要】

@SuppressWarningsメッセージ例
PHPMD.CyclomaticComplexityThe xx yy() has a Cyclomatic Complexity of 50. The configured cyclomatic complexity threshold is 10.

【重要】メソッドが複雑すぎ。循環的複雑度が11をこえている。リファクタして、ifやwhile、for、caseを減らそう。
PHPMD.NPathComplexityThe xx yy() has an NPath complexity of 512. The configured NPath complexity threshold is 200.

【重要】メソッドが複雑すぎ。コードの実行パス数が200をこえている。リファクタして、ifやwhile、for、caseを減らそう。
PHPMD.ExcessiveMethodLengthThe xx yy() has 200 lines of code. Current threshold is set to 100. Avoid really long methods.

【重要】メソッドが長すぎ、100行以内におさめよう。空行もカウントします。メソッドに分けよう。
PHPMD.ExcessiveClassLengthThe class xx has 2000 lines of code. Current threshold is 1000. Avoid really long classes.

【重要】クラスが長すぎ。1000行以内におさめよう。空行もカウントします。クラスを分けよう。
PHPMD.ExcessiveParameterListThe xx yy has 20 parameters. Consider reducing the number of parameters to less than 10.

メソッドの引数が多すぎ。10以内にしよう。
PHPMD.ExcessivePublicCountThe xx yy has 100 public methods and attributes. Consider reducing the number of public items to less than 45.

publicメソッド+publicプロパティが多すぎ。45以内にしよう。(get/setメソッド含む)
PHPMD.TooManyFieldsThe xx yy has 30 fields. Consider redesigning yy to keep the number of fields under 15.

クラスのプロパティが多すぎ。15以内にしよう。例えば、city、state、zipプロパティは、addressクラスにまとめたらどう?
PHPMD.TooManyMethodsThe xx yy has zz non-getter- and setter-methods. Consider refactoring yy to keep number of methods under 25.

メソッドが多すぎ。25以内にしよう。(get/setメソッドを除く)
PHPMD.TooManyPublicMethodsThe xx yy has 20 public methods. Consider refactoring yy to keep number of public methods under 10.

publicメソッドが多すぎ。10以内にしよう。(get/setメソッドを除く)
PHPMD.ExcessiveClassComplexityThe class xx has an overall complexity of 60 which is very high. The configured complexity threshold is 50.

メソッド数やメソッド複雑度から総合的に判断すると、クラスが複雑すぎ。WMC(Weighted Method Count)が50をこえている。

何千行もあるクラス、何百行もあるメソッドなんてふつうにあるよ

聞こえない...

controversial

@SuppressWarningsメッセージ例
PHPMD.Superglobalsxx accesses the super-global variable $_SESSION.

(メソッド内で)$_GET、$_SESSIONなどのスーパーグローバル変数にアクセスしないほうがいいよ。
PHPMD.CamelCaseClassNameThe class xx is not named in CamelCase.

クラス名をキャメルケースにしよう。
PHPMD.CamelCasePropertyNameThe property xx is not named in camelCase.

プロパティ名をキャメルケースにしよう。
PHPMD.CamelCaseMethodNameThe method xx is not named in camelCase.

メソッド名をキャメルケースにしよう。
PHPMD.CamelCaseParameterNameThe parameter xx is not named in camelCase.

引数名をキャメルケースにしよう。
PHPMD.CamelCaseVariableNameThe variable xx is not named in camelCase.

変数名をキャメルケースにしよう。

controversialは「物議をかもす」って意味だね

反対意見も多いってことね、スネークケースのほうが読みやすくて好みっていう人も多いわ

design

@SuppressWarningsメッセージ例
PHPMD.ExitExpressionThe xx yy() contains an exit expression.

exit()禁止。テストできないよ。
PHPMD.EvalExpressionThe xx yy() contains an eval expression.

eval()禁止。テストできないし、セキュリティリスクも高い。
PHPMD.GotoStatementThe xx yy() utilizes a goto statement.

goto禁止。
PHPMD.NumberOfChildrenThe xx yy has zz children. Consider to rebalance this class hierarchy to keep number of children under 15.

extendsした子クラスが多すぎ、15以下におさえよう。
PHPMD.DepthOfInheritanceThe xx yy has zz parents. Consider to reduce the depth of this class hierarchy to under 6.

extends階層が深すぎ。6以下におさえよう。
PHPMD.CouplingBetweenObjectsThe class xx has a coupling between objects value of 20. Consider to reduce the number of dependencies under 13.

使っているクラスが多すぎ。13以下にしよう。
PHPMD.DevelopmentCodeFragmentThe xx yy() calls the typical debug function var_dump() which is mostly only used during development.

var_dump()print_r()などの開発コードが残っているよ。本番コードでは削除しよう。
PHPMD.EmptyCatchBlockAvoid using empty try-catch blocks in xx.

catchが空だよ。
PHPMD.CountInLoopExpressionAvoid using count() function in yy loops.

ループ内でcount()しているよ。
例: for ($i = 0; $i <= count($arr); $i += 1)

for文でcount()使っているけど、何が悪いの?

たいがい foreach で置き換えできるでしょ。

それに、カウンタを使っている場合、複数の配列を操作していることが多くて、理解しづらいの。リファクタしたほうがいいかもれないから、確認したほうがいいってことね。

naming

@SuppressWarningsメッセージ例
PHPMD.LongClassName
Avoid excessively long class names like xx. Keep class name length under 40.

クラス名が長すぎ。40文字以下にしよう。
PHPMD.ShortClassNameAvoid classes with short names like xx. Configured minimum length is 3.

クラス名が短すぎ。3文字以上にしよう。
PHPMD.ShortVariableAvoid variables with short names like $x. Configured minimum length is 3.

変数名が短すぎ。3文字以上にしよう。forカウンタは除く。
PHPMD.LongVariableAvoid excessively long variable names like xx. Keep variable name length under 20.

プロパティ、引数、ローカル変数名が長すぎ。20文字以内にしよう。
PHPMD.ShortMethodNameAvoid using short method names like xx::yy(). The configured minimum method name length is 3.

メソッド名が短すぎ。3文字以上にしよう。
PHPMD.ConstructorWithNameAsEnclosingClassClasses should not have a constructor method with the same name as the class

コンストラクタは__constructメソッドを使うこと。PHP4スタイルのクラス名と同名メソッドは禁止。
PHPMD.ConstantNamingConventionsConstant xx should be defined in uppercase

クラスやinterfaceの定数名は、大文字にすること。
PHPMD.BooleanGetMethodNameThe 'xx()' method which returns a boolean should be named 'is…()' or 'has…()'

戻り値がbool型のメソッドは、'getX()' より、'isX()' 'hasX()' のほうがいいよ。

ローカル変数で1文字の $x、$y、2文字の $x1、$x2 とか使っているよ

そういう場合は警告抑止してもいいわね

unusedcode

@SuppressWarningsメッセージ例
PHPMD.UnusedPrivateFieldAvoid unused private fields such as 'xx'.

privateプロパティが使われていない。
PHPMD.UnusedLocalVariableAvoid unused local variables such as 'xx'.

ローカル変数が使われていない。
PHPMD.UnusedPrivateMethodAvoid unused private methods such as 'xx'.

privateメソッドが使われていない。
PHPMD.UnusedFormalParameterAvoid unused parameters such as 'xx'.

引数が使われていない。

当初は引数を使っていたんだけど、今は使わなくなった引数も警告されちゃうんだよね

すでにリリース済みのpublicやprotectedメソッドの場合は、リファクタしないほうがいいわね。

警告を抑止して、未使用になった理由やIssue番号をコメントに残しておいたらどうかしら。

タイトルとURLをコピーしました