Posted at
Quad incDay 15

PHPの静的解析いろいろ

More than 1 year has passed since last update.

Atomエディタをよく使っているのですが、phpmdプラグインがStaticAccessのエラーを出すのを止めたくて調べ始めたところ、こちらのページで静的解析ツールがいろいろとあることを知ったので、いくつか試してみました。


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


対応しているコーディングスタンダード

$ phpcs -i

The installed coding standards are MySource, PEAR, PHPCS, PSR1, PSR2, Squiz and Zend

デフォルトはPEARのようなので、PSR2を指定します。


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

ここに書かれているルールの中からチェックしたいものを指定して実行します。


実行

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


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


実行

$ 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 を作成します。


config.php

<?php

return [

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

"exclude_analysis_directory_list" => [
'vendor'
],
];


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


実行


実行

$ 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 で詳細な設定が可能なようです。


その他

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


アノテーション

class C

/** @var int */
const C = 42;

また、PHP7へ移行する際の互換性チェックも可能です。

ここを参照してください。


pfff

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

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


phpcpd

Copy/Paste Detector

https://github.com/sebastianbergmann/phpcpd

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


インストール

$ composer require "sebastian/phpcpd=*" --dev



実行

$ 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 とのこと。


インストール

$ composer require "ovr/phpsa" --dev



実行

$ 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 はもう少し追ってみようと思います。