コーディング規約のチュートリアル

コーディング規約のチュートリアル -- 独自の規約を作成するための手引き

導入

このチュートリアルでは、 規則をひとつだけ持った新しいコーディング規約を作成していきます。 作成する規則は、Perl 風のハッシュ記号によるコメントを禁止するものです。

コーディング規約用のディレクトリの作成

PHP_CodeSniffer で使用する規約は、すべてコーディング規約に従っている必要があります。 この規約とは、特定のディレクトリ配下にある単一のクラスでなければならないということです。 というわけなので、非常に簡単に作成することができます。 今回作成するコーディング規約は MyStandard という名前にしましょう。次のコマンドで、このコーディング規約用のディレクトリ構造を作成します。


$ mkdir MyStandard
$ mkdir MyStandard/Sniffs

    

注意 As this coding standard directory sits outside the main PHP_CodeSniffer directory structure, PHP_CodeSniffer will not show it as an installed standard when using the -i command line argument. If you want your standard to be shown as installed, create the MyStandard directory inside the PHP_CodeSniffer install:

注意

$ cd /path/to/PHP_CodeSniffer/CodeSniffer/Standards
$ mkdir MyStandard
$ mkdir MyStandard/Sniffs

    

MyStandard ディレクトリが 今回作成するコーディング規約そのものを表します。 サブディレクトリ Sniffs には、 このコーディング規約が使用するすべての sniff ファイルを保存します。

ディレクトリ構造ができたので、クラスファイルを追加していきましょう。 このファイルによって PHP_CodeSniffer がコーディング規約の情報を問い合わせられるようになり、 このディレクトリが sniff を含むものであることを示します。


$ cd MyStandard
$ touch MyStandardCodingStandard.php

    

MyStandardCodingStandard.php ファイルの内容は、 次のようになります。

<?php
/**
 * MyStandard コーディング規約
 *
 * PHP version 5
 *
 * @category  PHP
 * @package   PHP_CodeSniffer
 * @author    あなたの名前 <you@domain.net>
 * @license   http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence
 * @version   CVS: $Id: coding-standard-tutorial.xml,v 1.8 2008/07/11 23:33:24 takagi Exp $
 * @link      http://pear.php.net/package/PHP_CodeSniffer
 */

if (class_exists('PHP_CodeSniffer_Standards_CodingStandard', true) === false) {
    throw new PHP_CodeSniffer_Exception('Class PHP_CodeSniffer_Standards_CodingStandard not found');
}

/**
 * MyStandard コーディング規約
 *
 * @category  PHP
 * @package   PHP_CodeSniffer
 * @author    あなたの名前 <you@domain.net>
 * @license   http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence
 * @version   Release: @package_version@
 * @link      http://pear.php.net/package/PHP_CodeSniffer
 */
class PHP_CodeSniffer_Standards_MyStandard_MyStandardCodingStandard extends PHP_CodeSniffer_Standards_CodingStandard
{

}//end class
?>

注意 コーディング規約クラスは、この例のように空のままにしておくこともできます。 オーバーライドできるメソッドについての情報は、 コーディング規約クラスについてのドキュメント を参照ください。

規約の作成

各 sniff は、それぞれ個別の PHP ファイルを使用します。 その名前は、扱っている規約の内容がはっきりわかるようなものにします。 また、名前の最後は Sniff.php としなければなりません。 今回の場合は、PHP のファイル名は DisalowHashCommentsSniff.php とし、サブディレクトリ Commenting に配置します。 これにより、この規約がコメントに関するものであることを表しています。 以下のコマンドで、カテゴリおよび sniff ファイルを作成します。


$ cd Sniffs
$ mkdir Commenting
$ touch Commenting/DisallowHashCommentsSniff.php

    

注意 カテゴリ分けにどんなサブディレクトリを使用するかは決まっていません。 わかりやすい名前にしておき、あとで修正する際にそれを見つけやすいようにしておきましょう。

各 sniff ファイルは PHP_CodeSniffer_Sniff インターフェイスを実装している必要があります。これにより、 PHP_CodeSniffer はそれが sniff であることを知り、 起動時にインスタンスを作成します。 PHP_CodeSniffer_Sniff で定義されているメソッドは register() および process() のふたつで、これらは必ず実装しなければなりません。

register() および process() メソッド

register() メソッドでは、 処理の対象となるトークンの型を sniff に登録します。 PHP_CodeSniffer がこれらのトークンに遭遇すると、 PHP_CodeSniffer_File オブジェクト (現在チェック中のファイルを表します) およびスタック内でそのトークンが見つかった位置を指定して process() メソッドをコールします。

今回作成する sniff で対象としているのは、単一行コメントです。PHP_CodeSniffer がトークンの取得に使用している token_get_all() メソッドは、doc コメントと通常のコメントを別のトークン型として判定します。 そこで、doc コメントは今回のテストでは気にしないことにします。 register() メソッドは、単一のトークン型 T_COMMENT を返すようにする必要があります。

トークンスタック

sniff は、トークンに関するより多くの情報を取得するためにトークンスタックを使用することができます。 そのためには、PHP_CodeSniffer_File オブジェクトの getTokens() メソッドをコールします。 このメソッドは配列を返します。そのインデックスが、 トークンスタック内でのトークンの現れる位置を表します。 配列の各要素が、トークンを表します。 すべてのトークンは配列形式で、 codetype および content というインデックスを持っています。 code の値は、トークンの型を表す一意な整数値です。 type の値は、トークンの型を表す文字列です (たとえば 'T_COMMENT' はコメントトークンを表します)。 type は、その名前に対応するグローバルに定義された整数値も保持します。 また、content の値には、 コード内で現れたトークンの内容が含まれます。

注意 トークンによっては、上で説明したもの以外のインデックスを持っているものもあります。 PHP/CodeSniffer/File.php クラスのコメントで、 トークンの一覧とそのインデックスを参照ください。

エラーレポート

エラーが見つかったら、sniff はそれを通知しなければなりません。そのためには、 PHP_CodeSniffer_File オブジェクトの addError() メソッドをコールします。その際に、 適切なエラーメッセージを最初の引数、 エラーが発生した箇所のスタック内での位置を二番目の引数として指定します。 その違反がエラーというほど深刻ではない場合には、 addWarning() メソッドを使用します。

DisallowHashCommentsSniff.php

では、sniff の中身を書いていきましょう。 DisallowHashCommentsSniff.php ファイルの内容は、次のようになります。

<?php
/**
 * This sniff prohibits the use of Perl style hash comments.
 *
 * PHP version 5
 *
 * @category  PHP
 * @package   PHP_CodeSniffer
 * @author    Your Name <you@domain.net>
 * @license   http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence
 * @version   CVS: $Id: coding-standard-tutorial.xml,v 1.8 2008/07/11 23:33:24 takagi Exp $
 * @link      http://pear.php.net/package/PHP_CodeSniffer
 */

/**
 * This sniff prohibits the use of Perl style hash comments.
 *
 * An example of a hash comment is:
 *
 * <code>
 *  # This is a hash comment, which is prohibited.
 *  $hello = 'hello';
 * </code>
 * 
 * @category  PHP
 * @package   PHP_CodeSniffer
 * @author    Your Name <you@domain.net>
 * @license   http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence
 * @version   Release: @package_version@
 * @link      http://pear.php.net/package/PHP_CodeSniffer
 */
class MyStandard_Sniffs_Commenting_DisallowHashCommentsSniff implements PHP_CodeSniffer_Sniff
{


    /**
     * Returns the token types that this sniff is interested in.
     *
     * @return array(int)
     */
    public function register()
    {
        return array(T_COMMENT);

    }//end register()


    /**
     * Processes the tokens that this sniff is interested in.
     *
     * @param PHP_CodeSniffer_File $phpcsFile The file where the token was found.
     * @param int                  $stackPtr  The position in the stack where
     *                                        the token was found.
     *
     * @return void
     */
    public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr)
    {
        $tokens = $phpcsFile->getTokens();
        if ($tokens[$stackPtr]['content']{0} === '#') {
            $error = 'Hash comments are prohibited';
            $phpcsFile->addError($error, $stackPtr);
        }

    }//end process()


}//end class

?>

注意 デフォルトでは、PHP_CodeSniffer はすべての sniff が PHP のコードのみをチェックするものとみなします。 自作の sniff でサポートするトークナイザの一覧を指定し、 それらが PHP のコード用なのか JavaScript のコード用なのか両方用なのかを指定することができます。 それを設定するのが、自作の sniff 内のメンバ変数 $supportedTokenizers です。 次のコードを sniff に追加すると、PHP_CodeSniffer に対してそれが PHP と JavaScript の両方で使えることを指定できます。

注意
/**
 * A list of tokenizers this sniff supports.
 *
 * @var array
 */
public $supportedTokenizers = array(
                               'PHP',
                               'JS',
                              );

結果

これでコーディング規約が定義できたので、 ハッシュ形式のコメントを含むファイルの検証をしてみましょう。

ここでは次のような内容のテストファイルを使用するものとします。

<?php

# Check for valid contents.
if ($obj->contentsAreValid($array)) {
    $value = $obj->getValue();

    # Value needs to be an array.
    if (is_array($value) === false) {
        # Error.
        $obj->throwError();
        exit();
    }
}

?>

PHP_CodeSniffer を実行してこのファイルを新たなコーディング規約でチェックすると、 3 つのエラーが発生します。

$ phpcs --standard=/path/to/MyStandard Test.php

FILE: Test.php
--------------------------------------------------------------------------------
FOUND 3 ERROR(S) AND 1 WARNING(S) AFFECTING 3 LINE(S)
--------------------------------------------------------------------------------
 3 | ERROR | Hash comments are prohibited
 7 | ERROR | Hash comments are prohibited
 9 | ERROR | Hash comments are prohibited
--------------------------------------------------------------------------------

注意 コマンドラインで渡したコーディング規約ディレクトリが、絶対パスであったことに注意しましょう。 というのも、今回の規約は PHP_CodeSniffer のディレクトリ構造とは別の場所にインストールされているからです。 PHP_CodeSniffer の内部に作成した場合は、単純にその規約名を渡すだけでかまいません。

注意

$ phpcs --standard=MyStandard Test.php