4

PHP_CodeSniffer にクラス名のキャメルケースをチェックさせようとしていますが、キャメルケースのチェックは不可能なようです (専門用語を含む辞書がなけれ)。

私はインターネットをかき集めましたが、これまでに見た唯一のオプションは、文字列に爆発する一般的な区切り文字があるかどうかです-つまり、アンダースコア、単語間のスペースなど.

また、名前が正確に/常に各単語の間に区切り文字を含んでいる場合にのみ、チェックが正確になる可能性があるため、これでも役に立ちません。
「チェック」のポイントは、名前が正しくフォーマットされていないかどうかを判断することであり、これには正しく区切られていないことも含まれます。

また、PHP_CodeSniffer のリソースはまれであるか、ライター/開発者だけが理解できるほど基本的で専門的です。

現在の標準スニフ チェック

現在の Sniff の一部 (つまり、Squiz および PEAR 標準) でこのコードを見つけました。

if (PHP_CodeSniffer::isCamelCaps($functionName, false, true, false) === false) 

ただし、PHP_CodeSniffer コア コードを調べたところ、この関数は次のことしか実行しません。

// Check the first character first.
// Check that the name only contains legal characters.
// Check that there are not two capital letters next to each other.
// The character is a number, so it cant be a capital.

これらの基本的なチェックは、実際にはキャメルケースをまったくチェックしないため、意図された目的にはほぼ間違いなく役に立たないものの、何もないよりはましです。

質問

Sniff (または PHP スクリプト) は、文字列が 100% camelCase であるかどうかを識別するために、特定の文字列をチェックインする「単語」をどのように知ることができますか?


編集

正しいキャメルケース:class calculateAdminLoginCount

// Not camelCase
class calculateadminlogincount

// Partially camelCase
class calculateadminLogincount

isCamelCaps()上記の 2 つの例を関数 (または任意の PHP スクリプト) でキャッチするには どうすればよいでしょうか?

「単語」の概念がない場合、関数または PHP スクリプトは、その情報を (つまり、辞書から) フィードせずに、文字列から「個別の単語」をどのように識別できますか?

どこで爆発するか台本だとしても、何を元に爆発するのでしょうか?

PHP スクリプトは、その文字列内の異なる単語をどのように識別して、次のことを確認できます かclass calculateadminLogincount
?calculate admin Login count

isCamelCaps()関数

public static function isCamelCaps(
    $string,
    $classFormat=false,
    $public=true,
    $strict=true
) {

        // Check the first character first.
        if ($classFormat === false) {
            $legalFirstChar = '';
            if ($public === false) {
                $legalFirstChar = '[_]';
            }

            if ($strict === false) {
                // Can either start with a lowercase letter, 
                // or multiple uppercase
                // in a row, representing an acronym.
                $legalFirstChar .= '([A-Z]{2,}|[a-z])';
            } else {
                $legalFirstChar .= '[a-z]';
            }
        } else {
            $legalFirstChar = '[A-Z]';
        }

        if (preg_match("/^$legalFirstChar/", $string) === 0) {
            return false;
        }

        // Check that the name only contains legal characters.
        $legalChars = 'a-zA-Z0-9';
        if (preg_match("|[^$legalChars]|", substr($string, 1)) > 0) {
            return false;
        }

        if ($strict === true) {
            // Check that there are not two capital letters 
            // next to each other.
            $length          = strlen($string);
            $lastCharWasCaps = $classFormat;

            for ($i = 1; $i < $length; $i++) {
                $ascii = ord($string{$i});
                if ($ascii >= 48 && $ascii <= 57) {
                    // The character is a number, so it cant be a capital.
                    $isCaps = false;
                } else {
                    if (strtoupper($string{$i}) === $string{$i}) {
                        $isCaps = true;
                    } else {
                        $isCaps = false;
                    }
                }

                if ($isCaps === true && $lastCharWasCaps === true) {
                    return false;
                }

                $lastCharWasCaps = $isCaps;
            }
        }//end if

        return true;

    }//end isCamelCaps()

編集2

これが価値があるかどうか、または私が単に「いじって」「楽しんでいる」だけなのかどうか疑問に思っている人のための小さな情報:

オートローダが確実に動作するためには、ファイル/フォルダ構造と名前とクラス名が一致する必要があるため、クラス名は全体を通して正しく命名することが不可欠です。

スクリプトやクラスなどをロードできない場合 (もちろん)、そのような問題をチェックして処理するために Core コード自体をチェックしていますが、追加のスクリプト (PHP_CodeSniffer) を使用してすべてのファイルを実行し、潜在的な可能性がある場所を教えても問題はありません。問題は嘘かもしれません。
特に、コードベースが整頓され、正しく構造化され、全体に継続性があることも保証されるため、2 回目のチェックだけでも構いません。

4

2 に答える 2

0

クラス名がキャメルケースかどうかを「大まかに」識別しようとするスクリプトをいくつか作成しました。

私が自分のシナリオ用に書いたスクリプトのいくつかは、他の人には役に立ちません。例えば、それらは私自身の命名規則にあまりにも限定的です (ここには含めませんでした)。
したがって、私の実際のスクリプトのコレクションはすべて価値がありますが、以下のより一般的なスクリプトが他の人の助けになることを願っています.

たとえば、クラス名の前に小文字の単語を付けるので、そのプレフィックスの後の単語が大文字かどうかを確認します。
クラス名の前に特定の単語を付けない人 (ほとんどの人) にとって、文字列の最初の文字が小文字であることを確認するのは簡単です。

批判は大歓迎です。


大文字と小文字が混在するアルファのみを許可する

これにより、キャメルケース チェックに必要な大文字または小文字のアルファベット (Az) のみがクラス名に含まれるようになります (このスクリプトを削除する場合は、他のスクリプトを変更して非アルファ文字の可能性に対応する必要があります)。文字)。

/** Check string is only alpha (A-z) */
if (ctype_alpha($name) === false) {
  $error = '%s name must only contain alpha chars (A-z)';
  $phpcsFile->addError($error, $stackPtr, 'AlphaChars', $errorData);
  return;
}

2 つの大文字を一緒にすることはできません

一部の標準では頭字語などを許可していますが、厳密なキャメルケースではなく、読み取りの流れを壊しているため、私の標準ではこれを許可していません。

たとえばuserSitePHPLogin、無効でuserSitePhpLogin有効です。

(これを行うためのよりエレガントな方法がある可能性がありますが、問題なく動作し、PHP_CodeSniffer 用であるため、マイクロ最適化は必要ありません)

/** Check for uppercase chars together */
$nameUppercaseExplode = preg_split('/(?=[A-Z])/', $name);
$totalIllegalUpperChars = 0;

foreach ($nameUppercaseExplode as $namePiece) {
  if (strlen($namePiece) == 1) {
    $totalIllegalUpperChars++;
  }
}

if ($totalIllegalUpperChars >0) {
  $warning = 'Class name seems invalid; 
  Total '.$totalIllegalUpperChars.' uppercase chars not part of camelCase';
  $phpcsFile->addWarning($warning, $stackPtr, 'UppercaseTogether', $errorData);
}

たとえば、クラス名は次をDUserPHPUserclassLogin返します。

クラス名が無効のようです。キャメルケースの一部ではない合計 4 つの大文字

そのチェックで 1 アウトなので、完璧ではありません。
ただし、大文字が 1 つ以上一緒に出現する場合にのみ、警告が返されます。

たとえば、クラス名は次をclassDUserPhpUserLogin返します。

クラス名が無効のようです。キャメルケースの一部ではない合計 1 個の大文字

したがって、これにより、少なくとも開発者は名前を確認し、必要に応じて修正するように促されます。


大文字の合計が単語の合計よりも少ないかどうかを確認します

アイデアをくれたsjagrに感謝します。

「総単語数」はもちろん、各単語の平均 5 文字に基づいた「推定」数値です。公式の平均は平均単語あたり約 4.7 文字であるように思われるからです。

/** Loose check if total (guessed) words not match total uppercase chars */
$totalWordsGuess = ceil(strlen($name) / 5);
$totalUpperChars = strlen(preg_replace('![^A-Z]+!', '', $name));

// Pointless if only 1 word (camelCase not exist)
if ($totalWordsGuess >1) {

  // Remove the first word which should be lowercase
  // (first word should be checked in separate check above this one)
  $totalWordsGuess--;

  if ($totalUpperChars < $totalWordsGuess) {
    $warning = 'Expected '.$totalWordsGuess.' camelCase words in class name; 
    Found '.$totalUpperChars;
    $phpcsFile->addWarning($warning, $stackPtr, 'BadCamelCase', $errorData);
  }

}

私はそれをテストし、非常にうまく機能します (これは潜在的な問題に対する警告にすぎません)。

たとえば、クラス名を使用するUserLoginToomanywordsWithoutcamelCaseと、PHP_CodeSniffer は以下を返します。

クラス名にはキャメルケースの単語が 7 つ必要です。見つかった 5

あまりにも多くの誤検知が返された場合 (異なる開発者が異なる単語を使用するなど)、現在の「5」を少しずつ調整します。

編集:上記のスクリプトを更新しました:

  • 1 つの単語をキャメルケースにすることはできないため、複数の単語の場合にのみスクリプトが実行されるように条件を追加しました。
  • var --最初の単語が小文字であるため、大文字のカウントが存在しないことを考慮して、推測された単語の合計から 1 を差し引くコードを追加しました ( )。

returns最初の単語が小文字でない場合 は、最初の単語をチェックするために、この上に別のチェックが必要です。

于 2015-03-12T01:39:35.520 に答える
0

大文字と小文字が切り替わる場所で単語を分割することにより、関数名を分析して大文字を正しく使用することができます。元の関数名の各部分について、辞書または辞書 + 専門用語ファイル (「calc」、「url」、「admin」など (おそらく最初に専門用語を確認してください)) でそのサブワードを検索します。サブワードが失敗した場合、適切な大文字化が行われていません。

Solr または ElasticSearch を使用して、Lucene の WordDelimiterFilter を使用して単語を分割できます。これにより、大文字と小文字が変わるとサブワードが作成されます。

"PowerShot" -> "Power" "Shot" "LoginURL" => "Login" "URL"

これらの NoSQL データベースに単語を直接挿入して後で分析を行うか、(少なくとも ES では) 単に単語区切りトークン フィルターを使用して、実際に結果を保存せずにクエリを分割することができます。

http://www.elasticsearch.org/guide/en/elasticsearch/reference/current/analysis-word-delimiter-tokenfilter.html

https://wiki.apache.org/solr/AnalyzersTokenizersTokenFilters#solr.WordDelimiterFilterFactory

例:

calcAdminLogin => calc 管理者ログイン

calcadminlogin => calcadminlogin

「calc」や「admin」などの単語を含む補助辞書がある場合、最初の関数名は辞書に存在する 3 つの単語に分解されるため、キャメル ケースが正しいです。

2 番目の例では、'calcadminlogin' がディクショナリで見つからないため、キャメル ケーシングが正しくありません。

于 2015-03-09T21:42:11.317 に答える