PHP_CodeSnifferでコーディング規約に準拠しているかチェックをする | A Day In The Boy's Life

A Day In The Boy's Life

とあるエンジニアのとある1日のつぶやき。

開発規模が大きくなればなるほど、開発が複数の人により分散化されるため、コーディング規約をつくり、それに従って開発を進めることの重要性が増してきます。

経験の浅いメンバーがいれば、コーディングの仕方が統一されていなかったり、その重要性にも気づきにくいだけでなく、独自の実装方法を身につけてしまうと癖にもなってしまうため、定期的にコードレビューをして書き方を修正していく必要もあるでしょう。


しかし、コードレビューだけでは膨大な量のコードを見るのにもかなりの労力となってしまいますし、コーディング規約に準拠しているかどうかは、保守性の観点から重要ではあるものの自分のタスクや迫っているスケジュールに対して直結しなかったりもするため、後回しになったりどちらかというと「各々ちゃんとルールを守ってコーディングしてね!」という観点になってしまったりします。


ということで、PHPで開発する場合でコーディング規約に準拠しているかをプログラム自体がチェックしてくれるPEARのPHP_CodeSniffer を使ってセルフチェックができるようにしてみます。

なお、ここではPHPのコーディング規約として有名なPEAR標準コーディング規約Zend Framework PHP 標準コーディング規約 を中心に書いています。



PHP_CodeSnifferのインストールと利用方法


PHP_CodeSnifferのインストールはpearコマンドを通して行えます。

今回は、RC版ではあるものの最新の1.3.0を使用しています。


- pearコマンドを使ってPHP_CodeSnifferのインストール

$ pear install PHP_CodeSniffer-1.3.0RC1

インストールが完了するとphpcsというコマンドが利用可能になっています。

phpcsコマンド自体もPHPスクリプトですが、これを利用してコーディングチェックをすることができます。


$ phpcs -v --standard=PEAR hoge.php

上記のように-vオプション(結果の標準出力)を付け、--standardオプションにてチェックするコーディング規約の指定(上記の場合はPEARのコーディング規約によるチェック)、そして最後に対象のPHPスクリプトファイルを指定します。


--standardオプションで指定できるコーディング規約は、下記により確認できます。


$ phpcs -i
The installed coding standards are PHPCS, PEAR, MySource, Squiz and Zend

PEARとZend(Framework)に関してはわかるのですが、他の2つは・・・?


-vをつけることで標準出力にレポートの内容を出力しますが、ファイルに保存したり出力形式を変更することもできます。


$ phpcs --report=xml --report-file=hoge.xml --standard=PEAR hoge.php

結果は、なぜかPHP_CodeSnifferのインストールディレクトリ内に保存されますが。

その他にも幾つかオプションがあるので、詳細はヘルプ(phpcs --help)を参照してください。



PHP_CodeSnifferを使ってPEARとZend Frameworkのコーディング規約のチェックをする


ということで本題。

全てのコーディング規約をなめてたらかなりの量になるので主要なところを中心に書きます。


PHPタグに関するコーディング規約の確認


<?

echo "hello";

?>

----------------------------------------------------------------------
FOUND 2 ERROR(S) AFFECTING 1 LINE(S)
----------------------------------------------------------------------
 1 | ERROR | Short PHP opening tag used; expected "<?php" but found
   |       | "<?"
 1 | ERROR | Missing file doc comment
----------------------------------------------------------------------

----------------------------------------------------------------------
FOUND 2 ERROR(S) AFFECTING 2 LINE(S)
----------------------------------------------------------------------
 1 | ERROR | Short PHP opening tag used; expected "<?php" but found
   |       | "<?"
 5 | ERROR | A closing tag is not permitted at the end of a PHP file
----------------------------------------------------------------------

いきなり異なる結果が出ました。

どちらもPHPタグは短縮形ではなく、「<?php」の形式で使わなくてはならないというのは共通です(1行目)。

そして、Zend Frameworkの場合は、PHPの終了タグ(?>)は使用してはならないというのがあるので、そのコーディングエラーが表示されています。

PEARの場合、終了タグに関してのルールが記載されていません。

実際にPEAR本体のPEAR.phpには終了タグが書かれていませんが、その他のpearパッケージには終了タグを書いているものがあります。


PEARでのチェック時に出ているもう一つのエラーはドキュメントには必ずコメントを入れるというルールに従っていないというものです。

これは、PEARのコーディング規約に記載 があるものの、一方でZend Frameworkにもファイルの先頭にもドキュメントブロックを入れなければならないというルールがあるのにエラーとしてはでてきません。


文字列、配列に関するコーディング規約の確認


Zend Frameworkの方には文字列や変数の記述に関するコーディングルールがきっちり定義されています。

一方、PEARでは細かい規約を書いた項目がありません。

そして、PHP_CodeSnifferでも文字列に関してはチェックを行ってくれないようです。


<?php

$str = "hello " .
"world";

echo "${str}";

このコードはZend Frameworkでは正しい書き方ではない(※)のですが、チェックしてもエラーは出てくれません。

(というか、シェルスクリプトの変数の扱いのように${val}のような書き方ってできるんですね・・・・)

変数展開がないのならダブルクォートではなくシングルクォートを使うとか、文字列連結する場合は=の下に.を持ってくるようにするとか。


そして、配列の定義に関するコーディング規約もZendにはありますがチェックしてもエラーは出ません。

(PEARにはそもそもルールが記載されていない)


制御構造に関するコーディング規約の確認


<?php
for($i=0;$i<10;$i++) {
if($i==5){
echo "hello";
}
}

----------------------------------------------------------------------
FOUND 6 ERROR(S) AFFECTING 4 LINE(S)
----------------------------------------------------------------------
 2 | ERROR | Missing file doc comment
 3 | ERROR | Expected "for (...) {\n"; found "for(...) {\n"
 4 | ERROR | Line indented incorrectly; expected 4 spaces, found 0
 4 | ERROR | Expected "if (...) {\n"; found "if(...){\n"
 4 | ERROR | There must be a single space between the closing
   |       | parenthesis and the opening brace of a multi-line IF
   |       | statement; found 0 spaces
 5 | ERROR | Line indented incorrectly; expected at least 8 spaces,
   |       | found 0
----------------------------------------------------------------------

----------------------------------------------------------------------
FOUND 2 ERROR(S) AFFECTING 2 LINE(S)
----------------------------------------------------------------------
 3 | ERROR | Expected "for (...) {\n"; found "for(...) {\n"
 4 | ERROR | Expected "if (...) {\n"; found "if(...){\n"
----------------------------------------------------------------------


Zend Frameworkでチェックした結果は随分と少ないのですが、実際にはifやfor文の中での字下げに関するルールが存在したりします。

PEARの方はうるさく言われるんですが・・・。

共通してエラー表示されるのは、ifやfor文の条件を指定する()の前後には空白を1つ入れることというもの(3行目、4行目)。


その他にも、エラーはでないのですがZendの方では制御構造内の各条件の演算子の前後には空白を入れるというものがあったりしますが、エラーを検出してくれません。

関数定義、関数コールに関するコーディング規則の確認


<?php

foo(1,2,3);

function Foo($num1,$num2,$num3) {

return $num1+$num2+$num3;

}

----------------------------------------------------------------------
FOUND 7 ERROR(S) AFFECTING 4 LINE(S)
----------------------------------------------------------------------
 2 | ERROR | Missing file doc comment
 3 | ERROR | No space found after comma in function call
 3 | ERROR | No space found after comma in function call
 5 | ERROR | Function name "Foo" is invalid; consider "foo" instead
 5 | ERROR | Missing function doc comment
 5 | ERROR | Opening brace should be on a new line
 7 | ERROR | Line indented incorrectly; expected at least 4 spaces,
   |       | found 0
----------------------------------------------------------------------

----------------------------------------------------------------------
FOUND 3 ERROR(S) AFFECTING 3 LINE(S)
----------------------------------------------------------------------
 3 | ERROR   | No space found after comma in function call
 3 | ERROR   | No space found after comma in function call
 5 | WARNING | Consider putting global function "Foo" in a static
   |         | class
 5 | WARNING | Variable "num1" contains numbers but this is
   |         | discouraged
 5 | WARNING | Variable "num2" contains numbers but this is
   |         | discouraged
 5 | WARNING | Variable "num3" contains numbers but this is
   |         | discouraged
 5 | ERROR   | Opening brace should be on a new line
 7 | WARNING | Variable "num1" contains numbers but this is
   |         | discouraged
 7 | WARNING | Variable "num2" contains numbers but this is
   |         | discouraged
 7 | WARNING | Variable "num3" contains numbers but this is
   |         | discouraged
----------------------------------------------------------------------


こちらも随分と異なるチェック結果が出てきました。

共通のエラーとして表示されるのが、関数コール時の複数ある引数の区切りのコンマの後にはスペースを入れろというもの(3行目)。

そして、関数の始まりの{は改行してから書けというものです(5行目)。

異なる点は、PEARは関数内のタブをちゃんと入れろ(7行目)と言われ、そして関数名は小文字で始めろ(5行目)というエラーが出てきます。

Zend Frameworkでも関数名は小文字で始めるというルールがあるのですが、エラーが表示されません。


また、これはWARNINGとして出ているものですが、Zend Frameworkの方では関数をクラス内で定義しろというものが・・・(5行目)。

コーディング規則の中には、「グローバルスコープの関数はできるだけ使わないようにしましょう」とあるので、それによるものでしょうか。
もう一つ、Zend FrameworkのほうでWARNINGが出ているのは、変数名に数字を使うなというもの(7行目)です。変数名は英数字を使ってよいとはしていますが、数字を使うことはお勧めしないという風に規則には定義されています。


余談ですが、チェック結果の中でWARNINGを消したい場合は、下記のように-nオプションをつけて実行すれば表示されなくなります。


$ phpcs -v -n --standard=Zend hoge.php


クラス定義に関するコーディング規則の確認


<?php

$obj = new foo();
$obj->Bar();

class foo {

public $base = "hello";
private $str = "world";

function Bar() {
echo $this->base . $this->str;
}

}

----------------------------------------------------------------------
FOUND 12 ERROR(S) AFFECTING 6 LINE(S)
----------------------------------------------------------------------
  2 | ERROR | Missing file doc comment
  6 | ERROR | Class name must begin with a capital letter
  6 | ERROR | Missing class doc comment
  6 | ERROR | Opening brace of a class must be on the line after the
    |       | definition
  8 | ERROR | Line indented incorrectly; expected at least 4 spaces,
    |       | found 0
  9 | ERROR | Line indented incorrectly; expected at least 4 spaces,
    |       | found 0
  9 | ERROR | Private member variable "str" must be prefixed with an
    |       | underscore
 11 | ERROR | Method name "foo::Bar" is not in camel caps format
 11 | ERROR | Missing function doc comment
 11 | ERROR | Line indented incorrectly; expected 4 spaces, found 0
 11 | ERROR | Opening brace should be on a new line
 12 | ERROR | Line indented incorrectly; expected at least 8 spaces,
    |       | found 0
----------------------------------------------------------------------

----------------------------------------------------------------------
FOUND 3 ERROR(S) AFFECTING 3 LINE(S)
----------------------------------------------------------------------
  6 | ERROR | Opening brace of a class must be on the line after the
    |       | definition
  9 | ERROR | Private member variable "str" must contain a leading
    |       | underscore
 11 | ERROR | Opening brace should be on a new line
----------------------------------------------------------------------


PEARの方は、色々厳しく出ますね・・・。

共通のエラーとしては、クラスの初めの{は改行入れて書けというもの(6行目)と、プライベートスコープのメンバ変数は頭にアンダースコアを入れろというもの(9行目)、そして関数の初めの{は改行入れて書けというもの(11行目)です。


PEARの方は他にも、クラス名は大文字で始めろ(6行目)とか、関数名が大文字で始まることによりcamelCaps方式になっていない(11行目)とか、クラスや関数に関するコメントが書いてないよと言ったエラーが出てきます。



まとめ


現時点でのPHP_CodeSnifferでは、全体的にPEARはルールに沿ってかなり厳しくエラーが出てきますが、Zend Frameworkのコーディング規則のチェックは少し甘いかなというのが感想です。
規則は規則として、チェックする側はいいとこ取りしてくれればちょうどいいのにとか思ったり。


全体的に、規則には書いているけどエラーは出なかったりする部分があるので、このツールを使っても完璧に規則に沿ったコードが出てくるということはなさそうですが、目視チェックするよりは全然効率的です。

何よりも作ったプログラマー自身がセルフチェックできますからね。


ここで紹介した以外にもそれぞれのコーディング規則には細かなルールが設定されています。

こういったツールを使えば、コーディングのルールというものも覚えやすいかもしれませんね。