PHPの静的解析いろいろ

Atomエディタをよく使っているのですが、phpmdプラグインがStaticAccessのエラーを出すのを止めたくて調べ始めたところ、[こちら](https://github.com/exakat/php-static-analysis-tools)のページで静的解析ツールがいろいろとあることを知ったので、いくつか試してみました。

# Atomのプラグインでダウンロードが多そうなもの

まずはAtomのLinterでよく使われていそうなものから。
インストール方法は各URLを参照してください。

## PHP lint

http://php.net/manual/en/features.commandline.options.php

PHP標準のシンタックスチェック機能です。
構文に誤りがないかのチェックのみなので、ひどいコードでもパスします。

```:使い方
php -l <filenmae>
```

**プラグイン**
https://atom.io/packages/linter-php


## phpcs

**PHP Code Snifer**
https://github.com/squizlabs/PHP_CodeSniffer

指定したコーディングスタンダードに適合しているかをチェックします。

**プラグイン**
https://atom.io/packages/linter-phpcs


```console:対応しているコーディングスタンダード
$ phpcs -i
The installed coding standards are MySource, PEAR, PHPCS, PSR1, PSR2, Squiz and Zend
```
デフォルトはPEARのようなので、PSR2を指定します。

```console:PSR-2でチェック実行
$ phpcs --standard=PSR2 Illuminate/Auth/AuthServiceProvider.php 

FILE: ...or/laravel/framework/src/Illuminate/Auth/AuthServiceProvider.php
----------------------------------------------------------------------
FOUND 1 ERROR AFFECTING 1 LINE
----------------------------------------------------------------------
 57 | ERROR | [x] Only one argument is allowed per line in a
    |       |     multi-line function call
----------------------------------------------------------------------
PHPCBF CAN FIX THE 1 MARKED SNIFF VIOLATIONS AUTOMATICALLY
----------------------------------------------------------------------

Time: 210ms; Memory: 4Mb
```

## phpmd

PHP Mess Detection
https://phpmd.org/documentation/creating-a-ruleset.html

考えられるバグ、最適でないコード、複雑すぎる表現、未使用のパラメータ・メソッド・プロパティ等の潜在的な問題を検出します。

**プラグイン**
https://atom.io/packages/linter-phpmd

[ここ](https://phpmd.org/rules/index.html)に書かれているルールの中からチェックしたいものを指定して実行します。

```console:実行
$ phpmd wp-login.php text codesize

/path/to/wordpress/wp-login.php:33	The function login_header() has a Cyclomatic Complexity of 20. The configured cyclomatic complexity threshold is 10.
/path/to/wordpress/wp-login.php:33	The function login_header() has an NPath complexity of 52224. The configured NPath complexity threshold is 200.
/path/to/wordpress/wp-login.php:33	The function login_header() has 175 lines of code. Current threshold is set to 100. Avoid really long methods.
/path/to/wordpress/wp-login.php:278	The function retrieve_password() has a Cyclomatic Complexity of 10. The configured cyclomatic complexity threshold is 10.
```

Atomの場合は、プロジェクトルートに以下のようなファイルを配置して、プラグインの設定画面にファイル名を入力します。ルールは除外したり、独自の設定値で上書き可能です。

```xml:phpmd.xml
<?xml version="1.0"?>
<ruleset name="My 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">
    <rule ref="rulesets/cleancode.xml">
        <exclude name="StaticAccess" />
    </rule>
    <rule ref="rulesets/codesize.xml" />
    <rule ref="rulesets/controversial.xml" />
    <rule ref="rulesets/design.xml" />
    <rule ref="rulesets/naming.xml" />
    <rule ref="rulesets/unusedcode.xml" />
</ruleset>
```


## php7cc

**PHP 7 Compatibility Checker**
https://github.com/sstalle/php7cc

コードがPHP7に対応しているかをチェックするツールです。 
**プラグイン**
https://atom.io/packages/linter-php7cc


```console:実行
$ php7cc wp-includes/

File: /path/to/wordpress/wp-includes/atomlib.php
> Line 162: Removed function "split" called
    split(':', $name);
> Line 241: Removed function "split" called
    split(':', $name);
> Line 316: Removed function "split" called
    split(':', $qname);


File: /path/to/wordpress/wp-includes/capabilities.php
> Line 429: Function argument(s) returned by "func_get_args" might have been modified
    func_get_args();
> Line 456: Function argument(s) returned by "func_get_args" might have been modified
    func_get_args();
> Line 486: Function argument(s) returned by "func_get_args" might have been modified
    func_get_args();
> Line 508: Function argument(s) returned by "func_get_args" might have been modified
    func_get_args();

  :
```

# Githubでスターが多いもの

ここからはスターが多かったものを見てみます。

## phan

https://github.com/etsy/phan

PHPの生みの親、Rasmusさんが作ったようです。

### インストール

```:macにインストール
brew update
brew install php70 php70-ast phan
```

### 設定ファイルを用意

プロジェクトルートに `.phan/config.php` を作成します。

```php:config.php
<?php

return [

    'directory_list' => [
        'app',
    ],

    "exclude_analysis_directory_list" => [
        'vendor'
    ],
];
```
`directory_list` は解析対象のディレクトリのリストで、 `exclude_analysis_directory_list` に定義されたディレクトリを除外した後、残りのファイルは静的にエラーを分析されます。



### 実行

```console:実行
$ phan -ophan.log
```

```:phan.log
  :
app/Http/Controllers/BaseController.php:10 PhanUndeclaredTypeParameter Parameter of undeclared type \Illuminate\Http\Request
app/Http/Controllers/BaseController.php:12 PhanUndeclaredProperty Reference to undeclared property request
app/Http/Controllers/BaseController.php:13 PhanUndeclaredClassMethod Call to method getMonolog from undeclared class \Log
app/Http/Controllers/BaseController.php:14 PhanUndeclaredClassMethod Call to method __construct from undeclared class \Monolog\Processor\IntrospectionProcessor
  :
```

もう少し設定の余地がありそうな結果となりました。 config.php で詳細な設定が可能なようです。

### その他

型のアノテーションを記述することで、より正確に解析を行うことができるようです

```php:アノテーション
class C
   /** @var int */
   const C = 42;
```

また、PHP7へ移行する際の互換性チェックも可能です。
[ここ](https://github.com/etsy/phan/wiki/Incrementally-Strengthening-Analysis)を参照してください。



## pfff

Facebook製のコード解析、ビジュアライズ、style-preserving source transformation（スタイルを保ったソースコードの変換？？フォーマットのことかな）が可能で、PHP以外にも多くの言語に対応しているようです。

ただインストールが激ムズで、makeが通らなくて断念しました。。。


## phpcpd

Copy/Paste Detector
https://github.com/sebastianbergmann/phpcpd

名前のとおり、重複したコードを検知可能なツールです。

```console:インストール
$ composer require "sebastian/phpcpd=*" --dev
```

```console:実行
$ phpcpd wp-includes/class-snoopy.php 
phpcpd 2.0.4 by Sebastian Bergmann.

Found 4 exact clones with 125 duplicated lines in 1 files:

  -	/wp-includes/class-snoopy.php:165-195
 	/wp-includes/class-snoopy.php:225-255
 
  -	/wp-includes/class-snoopy.php:133-155
 	/wp-includes/class-snoopy.php:285-307
 
  -	/wp-includes/class-snoopy.php:181-218
 	/wp-includes/class-snoopy.php:339-376
 
  -	/wp-includes/class-snoopy.php:317-353
 	/wp-includes/class-snoopy.php:384-420
 
9.95% duplicated lines out of 1256 total lines of code.

Time: 28 ms, Memory: 6.00MB
```


## phpsa

Smart Analyzer for PHP
https://github.com/ovr/phpsa

「複雑な分析を目的とした」ツールで、JetBrain社がスポンサー？のようです。
まだ `early alpha state` とのこと。

```console:インストール
$ composer require "ovr/phpsa" --dev
```

```console:実行
$ vendor/bin/phpsa check app/Http/Controllers/Auth/

Scanning directory app/Http/Controllers/Auth/
Found 4 files

Notice:  Missing Docblock in app/Http/Controllers/Auth/ForgotPasswordController.php on 8 [missing_docblock]

	 class ForgotPasswordController extends Controller 

Notice:  Missing Docblock in app/Http/Controllers/Auth/LoginController.php on 8 [missing_docblock]

	 class LoginController extends Controller 

Notice:  Missing Docblock in app/Http/Controllers/Auth/RegisterController.php on 10 [missing_docblock]

	 class RegisterController extends Controller 
```

# 終わりに

個人的には phpcs と phpmd をメインに、PHP7に移行する際は php7cc を使ってみます。
phan はもう少し追ってみようと思います。