usages/phpUnderControl/WebCoding 1st/05日目

提供: スゴイようぃっきー!

usages / phpUnderControl / WebCoding 1st / 05日目

目次

usages/phpUnderControl/WebCoding 1st/05日目 : PHP_CodeSniffer用のオリジナルのコーディングを作る

今回の目標は以下のとおりです。

  • 一部のPEAR、Squizのコーディング規約を除外したい
  • 一部のPEAR、Sauizのコーディング規約を修正して使いたい
  • オリジナルのコーディング規約を新たに作成したい

除外の場合、1日目で用意した、オリジナルのコーディング規約定義ファイルStandards/SUGOIYO/PHPCSCodingStandard.phpのgetExcludedSniffsに追加するだけで良いのですが、気をつけないといけないのは、除外する場合はPHPファイル単位でしか指定できないようなので、複数の処理をしている中の一部だけを修正・除外したい場合は、オリジナルのスクリプトを直接改変するか、複製を用意してオリジナルコーディング規約の中に配置する方法が必要です。

除外設定(getExcludedSniffs)で足りる例

たとえば、シングルクォーテーションとダブルクォーテーションの記述方法が適切かどうかを検査しているSquiz.Strings.DoubleQuoteUsageを例にとります。

私としては、どちらもあまり気にせずに書きたいと思うので、除外したいのですが、実際に規約を検査しているファイルを覗きます。

PHP/CodeSniffer/Standards/Squiz/Sniffs/Strings/DoubleQuoteUsageSniff.php

<?php
/**
* Squiz_Sniffs_Strings_DoubleQuoteUsageSniff.
*
* PHP version 5
*
* @category PHP
* @package PHP_CodeSniffer
* @author Greg Sherwood <gsherwood@squiz.net>
* @author Marc McIntyre <mmcintyre@squiz.net>
* @copyright 2006 Squiz Pty Ltd (ABN 77 084 670 600)
* @license http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence
* @version CVS: $Id: DoubleQuoteUsageSniff.php 289078 2009-10-02 02:01:28Z sebastian $
* @link http://pear.php.net/package/PHP_CodeSniffer
*/

 
/**
* Squiz_Sniffs_Strings_DoubleQuoteUsageSniff.
*
* Makes sure that any use of Double Quotes ("") are warranted.
*
* @category PHP
* @package PHP_CodeSniffer
* @author Greg Sherwood <gsherwood@squiz.net>
* @author Marc McIntyre <mmcintyre@squiz.net>
* @copyright 2006 Squiz Pty Ltd (ABN 77 084 670 600)
* @license http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence
* @version Release: 1.2.2
* @link http://pear.php.net/package/PHP_CodeSniffer
*/

class Squiz_Sniffs_Strings_DoubleQuoteUsageSniff implements PHP_CodeSniffer_Sniff
{
 
 
/**
* Returns an array of tokens this test wants to listen for.
*
* @return array
*/

public function register()
{
return array(
T_CONSTANT_ENCAPSED_STRING,
T_DOUBLE_QUOTED_STRING,
);
 
}//end register()
 
 
/**
* Processes this test, when one of its tokens is encountered.
*
* @param PHP_CodeSniffer_File $phpcsFile The file being scanned.
* @param int $stackPtr The position of the current token
* in the stack passed in $tokens.
*
* @return void
*/

public function process(PHP_CodeSniffer_File $phpcsFile, $stackPtr)
{
$tokens = $phpcsFile->getTokens();
 
// The use of variables in double quoted strings is not allowed.
if ($tokens[$stackPtr]['code'] === T_DOUBLE_QUOTED_STRING) {
$stringTokens = token_get_all('<?php '.$tokens[$stackPtr]['content']);
foreach ($stringTokens as $token) {
if (is_array($token) === true && $token[0] === T_VARIABLE) {
$error = 'Variable "'.$token[1].'" not allowed in double quoted string; use concatenation instead';
$phpcsFile->addError($error, $stackPtr);
}
}
 
return;
}//end if
 
$workingString = $tokens[$stackPtr]['content'];
 
// Check if it's a double quoted string.
if (strpos($workingString, '"') === false) {
return;
}
 
// Make sure it's not a part of a string started above.
// If it is, then we have already checked it.
if ($workingString[0] !== '"') {
return;
}
 
// Work through the following tokens, in case this string is stretched
// over multiple Lines.
for ($i = ($stackPtr + 1); $i < $phpcsFile->numTokens; $i++) {
if ($tokens[$i]['type'] !== 'T_CONSTANT_ENCAPSED_STRING') {
break;
}
 
$workingString .= $tokens[$i]['content'];
}
 
$allowedChars = array(
'\0',
'\n',
'\r',
'\f',
'\t',
'\v',
'\x',
'\'',
);
 
foreach ($allowedChars as $testChar) {
if (strpos($workingString, $testChar) !== false) {
return;
}
}
 
$error = "String $workingString does not require double quotes; use single quotes instead";
$phpcsFile->addError($error, $stackPtr);
 
}//end process()
 
 
}//end class
 
?>

このプログラムを見ると、エラー判定($phpcsFile->addError している箇所)が2箇所だということがわかります。
始めの判定は、どうやら配列変数をダブルクォーテーション内に書いた場合にエラーとしているようです。これは特に除外したい内容でもありませんが、私にとっては除外しても気になるものではありません。

2番目にある判定が、ダブルクォーテーションの必要が無い文字列なので、シングルクォーテーションを使いなさいという規約で、この規約については除外したいと思っているものです。

このDoubleQuoteUsageSniff.phpでは2つの規約判定があり、両方とも無くしても良いと私は思えるので、Standards/SUGOIYO/PHPCSCodingStandard.phpに以下のような記述を追記することで、処理を除外することができます。記述例は以下のとおりです。

public function getExcludedSniffs()
{
return array(
'Squiz/Sniffs/Strings/DoubleQuoteUsageSniff.php',
);
 
}//end getExcludedSniffs()

修正が必要な例

前述のように、getExcludedSniffsを用いた除外で事足りる場合は良いのですが、例えば、一部の処理だけ修正をしたいということもあります。
この場合、PEARやSquizのSniffファイルを直接変更しても良いのですが、それではpear upgradeの際に面倒な気がします。
そこで、一部修正する場合の方法について説明します。
例としてはコメントは大文字で始めなさいというInline comments must start with a capital letter : Squiz.Commenting.InlineComment だけを無効にします。

まずは除外する

前述のように、getExcludedSniffsを利用して一部修正したいと思うSniffを一旦全て除外します。

public function getExcludedSniffs()
{
    return array(
            // 前略
            'Squiz/Sniffs/Commenting/InlineCommentSniff.php',
            // 後略
           );

}//end getExcludedSniffs()


複製を作成してオリジナル規約のSniffs配下に配置する。

Squiz/Sniffs/Commenting/InlineCommentSniff.php を SUGOIYOコーディング規約に複製します。
つまり、SUGOIYO/Sniffs/Commenting/InlineCommentSniff.php を作成します。

次に、クラス名を修正します。
Squiz_ とある記述を SUGOIYO_ に置換します。
これで、Class名が変更になり同様の規約検査を行えます。

次にコードを読み、大文字で始めなさいと検査している箇所を見つけ出します。

if (preg_match('|[A-Z]|', $commentText[0]) === 0) {
$error = 'Inline comments must start with a capital letter';
$phpcsFile->addError($error, $topComment);
}

上述部分をコメントアウトすれば作業は終了です。
これでコメントを大文字で始めなさいというという規約を無効化することができました。
サンプルはこちらにありますので、ご参考に。
http://pci01/viewvc/svnrepos/projects/MySniffs/trunk/src/SUGOIYO/Sniffs/Commenting/InlineCommentSniff.php?view=markup

オリジナルの検査規約とのdiffは以下のとおりです。大文字で始めよの他に、末尾に関する規約も無効化しています。
--- Squiz/Sniffs/Commenting/InlineCommentSniff.php 2010-06-05 21:39:40.000000000 +0900

 +++ SUGOIYO/Sniffs/Commenting/InlineCommentSniff.php	2010-07-04 13:33:19.000000000 +0900
 @@ -1,6 +1,6 @@
  <?php
  /**
 - * Squiz_Sniffs_Commenting_InlineCommentSniff.
 + * SUGOIYO_Sniffs_Commenting_InlineCommentSniff.
   *
   * PHP version 5
   *
 @@ -8,6 +8,7 @@
   * @package   PHP_CodeSniffer
   * @author    Greg Sherwood <gsherwood@squiz.net>
   * @author    Marc McIntyre <mmcintyre@squiz.net>
 + * @author    sugoiyo72 <sugoiyo72@sugoiyo.net>
   * @copyright 2006 Squiz Pty Ltd (ABN 77 084 670 600)
   * @license   http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence
   * @version   CVS: $Id: InlineCommentSniff.php 291580 2009-12-02 03:40:18Z squiz $
 @@ -15,7 +16,7 @@
   */
  
  /**
 - * Squiz_Sniffs_Commenting_InlineCommentSniff.
 + * SUGOIYO_Sniffs_Commenting_InlineCommentSniff.
   *
   * Checks that there is adequate spacing between comments.
   *
 @@ -23,12 +24,13 @@
   * @package   PHP_CodeSniffer
   * @author    Greg Sherwood <gsherwood@squiz.net>
   * @author    Marc McIntyre <mmcintyre@squiz.net>
 + * @author    sugoiyo72 <sugoiyo72@sugoiyo.net>
   * @copyright 2006 Squiz Pty Ltd (ABN 77 084 670 600)
   * @license   http://matrix.squiz.net/developer/tools/php_cs/licence BSD Licence
   * @version   Release: 1.2.2
   * @link      http://pear.php.net/package/PHP_CodeSniffer
   */
 -class Squiz_Sniffs_Commenting_InlineCommentSniff implements PHP_CodeSniffer_Sniff
 +class SUGOIYO_Sniffs_Commenting_InlineCommentSniff implements PHP_CodeSniffer_Sniff
  {
  
      /**
 @@ -214,10 +216,12 @@
              return;
          }
  
 +        /*
          if (preg_match('|[A-Z]|', $commentText[0]) === 0) {
              $error = 'Inline comments must start with a capital letter';
              $phpcsFile->addError($error, $topComment);
          }
 +        */
  
          $commentCloser   = $commentText[(strlen($commentText) - 1)];
          $acceptedClosers = array(
 @@ -226,6 +230,7 @@
                              'or question marks' => '?',
                             );
  
 +        /*
          if (in_array($commentCloser, $acceptedClosers) === false) {
              $error = 'Inline comments must end in';
              foreach ($acceptedClosers as $closerName => $symbol) {
 @@ -235,6 +240,7 @@
              $error = rtrim($error, ',');
              $phpcsFile->addError($error, $stackPtr);
          }
 +        */
  
          // Finally, the line below the last comment cannot be empty.
          $start = false;

除外・修正総括

実施した作業について簡単にまとめます。

コメント行の長さをマルチバイトに対応

コメント行の長さを検査するFiles/LineLengthSniff.phpについて、マルチバイトの対応を行いました。
変更前

$lineLength = strlen($lineContent);

変更後

$lineLength = mb_strwidth($lineContent);

docコメントの@categoryを必須から任意に変更

変更前

protected $tags = array(
'category' => array(
'required' => true,
'allow_multiple' => false,
'order_text' => 'precedes @package',
),

変更後

protected $tags = array(
'category' => array(
'required' => false,
'allow_multiple' => false,
'order_text' => 'precedes @package',
),

コメントの大文字始まり、末尾文字指定を無効化

前述のとおりです。

除外した規約一覧

SUGOIYOCodingStandard.php で除外している規約は以下のとおりです。

public function getExcludedSniffs()
{
return array(
'Squiz/Sniffs/Classes/ClassFileNameSniff.php',
'Squiz/Sniffs/Classes/ValidClassNameSniff.php',
'Squiz/Sniffs/Commenting/ClassCommentSniff.php',
'Squiz/Sniffs/Commenting/FileCommentSniff.php',
'Squiz/Sniffs/Commenting/FunctionCommentSniff.php',
'Squiz/Sniffs/Commenting/VariableCommentSniff.php',
'Squiz/Sniffs/ControlStructures/SwitchDeclarationSniff.php',
'Squiz/Sniffs/Files/FileExtensionSniff.php',
'Squiz/Sniffs/NamingConventions/ConstantCaseSniff.php',
'Squiz/Sniffs/WhiteSpace/ScopeIndentSniff.php',
'Squiz/Sniffs/Strings/ConcatenationSpacingSniff.php',
'Squiz/Sniffs/Commenting/InlineCommentSniff.php',
'Squiz/Sniffs/Operators/ComparisonOperatorUsageSniff.php',
'Squiz/Sniffs/PHP/ForbiddenFunctionsSniff.php',
'Squiz/Sniffs/Strings/DoubleQuoteUsageSniff.php',
'PEAR/Sniffs/Commenting/FileCommentSniff.php',
'PEAR/Sniffs/Commenting/ClassCommentSniff.php',
'PEAR/Sniffs/Files/LineLengthSniff.php',
);
 
}//end getExcludedSniffs()

ベースになっているPHPCSに追記したものだけを列挙すると以下のようになります。

'Squiz/Sniffs/Strings/ConcatenationSpacingSniff.php',
'Squiz/Sniffs/Commenting/InlineCommentSniff.php',
'Squiz/Sniffs/Operators/ComparisonOperatorUsageSniff.php',
'Squiz/Sniffs/PHP/ForbiddenFunctionsSniff.php',
'Squiz/Sniffs/Strings/DoubleQuoteUsageSniff.php',
'PEAR/Sniffs/Commenting/FileCommentSniff.php',
'PEAR/Sniffs/Commenting/ClassCommentSniff.php',
'PEAR/Sniffs/Files/LineLengthSniff.php',

オリジナルのコーディング規約用に作成したファイル

SUGOIYO
│ SUGOIYOCodingStandard.php

└─Sniffs
├─Commenting
│ ClassCommentSniff.php
│ FileCommentSniff.php
│ InlineCommentSniff.php

└─Files
LineLengthSniff.php

オリジナルの新規規約を作成する。

おそらく、新規の規約をスクラッチから書くことはほとんど無くて、既存のPEARやSquizの定義を修正するだけで事足りるのではないかと思います。

次回

コーディング規約についてJavaScriptやCSSについては手を付けていませんし、検査しているコード量が少ないので、最適化は今後も必要かと思いますが、PHP_CodeSnifferを使ったコーディング規約の検査はこのあたりで一旦終わりにして、いよいよPHPUnitを利用しながらリファクタリングに挑戦したいと思います。

prev | 05日目


Google AdSense