4

我试图让 PHP_CodeSniffer 检查类名中的 camelCase,但在我看来,camelCase 检查是不可能的(没有字典,包括技术词)。

我已经在互联网上搜索过,但到目前为止,我看到的唯一选择是字符串是否有一些通用的分隔符可以从中分解——即下划线、单词之间的空格等。

甚至这也没有用,因为只有在名称准确/始终包含每个单词之间的分隔符时,检查才能准确。
“检查”的重点是确定名称是否格式不正确,这可能包括不正确分隔。

此外,PHP_CodeSniffer 上的资源要么很少见,要么非常基础和技术性强,只有作者/开发人员才能理解。

当前标准嗅探检查

我在一些当前的 Sniffs(即 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.

这些基本检查总比没有好,尽管可以说对于它们的预期目的毫无用处,因为它们根本没有真正检查 camelCase。

问题

嗅探器(或即 PHP 脚本)如何知道在给定字符串中检查哪些“单词”以识别字符串是否为 100% 驼峰式?


编辑

例子

正确的驼峰式:class calculateAdminLoginCount

// Not camelCase
class calculateadminlogincount

// Partially camelCase
class calculateadminLogincount

isCamelCaps()函数(或任何 PHP 脚本)如何捕获上述两个示例?

函数或 PHP 脚本如何从字符串中识别“单独的单词”,当它没有“单词”的概念而不提供该信息(即来自字典)时?

即使一个脚本在哪里爆炸,它会根据什么爆炸?

采取class calculateadminLogincount
任何PHP脚本如何识别该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

对于那些想知道这是否值得,或者我只是在“玩弄”和“玩得开心”的人的一些信息:

必须在整个过程中正确命名类名,因为文件/文件夹结构以及名称和类名必须匹配才能使自动加载器可靠地工作。

虽然我检查了核心代码本身以检查和处理无法加载脚本、类等的此类问题(当然),但附加脚本(PHP_CodeSniffer)运行所有文件并告诉我潜在的位置并没有错问题可能在于。
即使只是为了进行第二次检查,尤其是因为它还可以确保代码库整洁、结构正确并且始终具有连续性。

4

2 回答 2

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 个单词,这些单词将出现在字典中,因此骆驼大小写是正确的。

在第二个示例中,将无法在字典中找到“calcadminlogin”,因此驼峰式大小写不正确。

于 2015-03-09T21:42:11.317 回答
0

我制作了一些脚本来尝试“松散地”识别类名是否为 camelCase。

我为我的场景编写的一些脚本对其他人没有帮助,例如它们对我自己的命名约定具体了(我没有在这里包括它们)。
所以我实际收集的脚本让这一切都值得,但希望下面更通用的脚本对其他人有所帮助。

例如,我用小写单词作为类名的前缀,因此我检查该前缀后面的单词是否为大写。
对于那些不使用特定单词作为类名前缀的人(大多数人),很容易检查字符串的第一个字符是否为小写。

非常欢迎批评。


只允许混合大小写字母

这可确保类名仅包含大写或小写字母 (Az),这是 camelCase 检查所需的(如果删除此脚本,则需要更改其他脚本以适应潜在的非 alpha字符)。

/** 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;
}

没有两个大写字符在一起

一些标准允许使用首字母缩略词等,但是我的标准不允许这样做,因为它不是严格的驼峰式,并且会破坏阅读流程。

eguserSitePHPLogin是无效的,并且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 个大写字符不属于 camelCase

它并不完美,因为它是该检查的 1。
但只有在至少出现 1 次大写字母时才会返回警告。

例如类名classDUserPhpUserLogin返回:

类名似乎无效;总共 1 个大写字符不属于 camelCase

因此,这至少会提示开发人员检查名称并根据需要进行修复。


检查总大写字符是否小于总字数

感谢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 个单词时运行,因为 1 个单词不能是驼峰式。
  • 添加了代码以从总猜测单词中减去 1 ( var --),以说明第一个单词是小写的,因此不存在大写计数。

您应该在此上方进行单独检查以检查第一个单词,returns如果第一个单词不是小写的话。

于 2015-03-12T01:39:35.520 回答