コーディング規約のチュートリアル -- 独自の規約を作成するための手引き
導入
このチュートリアルでは、
規則をひとつだけ持った新しいコーディング規約を作成していきます。
作成する規則は、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() メソッドをコールします。
このメソッドは配列を返します。そのインデックスが、
トークンスタック内でのトークンの現れる位置を表します。
配列の各要素が、トークンを表します。
すべてのトークンは配列形式で、
code、type および
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 の両方で使えることを指定できます。
注意
<?php
/**
* 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
|
|
設定オプション (Previous)
|
(Next) コーディング規約クラスのメソッド
|
|
|
Download Documentation
|
Last updated: Sun, 05 Oct 2008 |
|
Do you think that something on this page is wrong? Please file a bug report or add a note.
|
| User Notes: |
Note by: pg.allen@gmail.com
I ran into an interesting use case; I'd like to use the normal PEAR install, but be able to define custom standards that are part of our cvs project for the code base. Thus, CodeSniffer hits a failure when it can't include my custom sniffs because they aren't in the normal place and also aren't in php.ini's include_path. Since each developer needs to run phpcs against local files in various cvs sandboxes, we can't just include the path in php.ini (it varies). I've implemented a fix, a command-line option called "--sniffs-dir" that tells getSniffFiles() to also look in the --sniffs-dir directory. In CLI.php, I also catch that option and append it to the include_path. Seems to work fine. Is anyone interested in adding this feature to this awesome tool?
Note by: Don Turner
When creating a new standard e.g. MyStandard you need to put the class MyStandardCodingStandard.php into the MyStandard folder which you have just created.
This took me a bit of time to figure out, perhaps someone could update the documentation to reflect this.
|
|