Я пытаюсь заставить 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.
Как может Sniff (или, например, PHP-скрипт) знать, какие «слова» нужно проверить в данной строке, чтобы определить, является ли строка 100% camelCase?
Правильный camelCase: class calculateAdminLoginCount
// Not camelCase
class calculateadminlogincount
// Partially camelCase
class calculateadminLogincount
Как можно isCamelCaps()
функция (или любой PHP-скрипт в этом отношении) ловит два приведенных выше примера?
Как может функция или PHP-скрипт идентифицировать «отдельные слова» из строки, если в ней нет понятия «слова», не передавая ей эту информацию (т.е. из словаря)?
Даже если сценарий, где взорваться, что бы он взорвался на основе?
принимать class calculateadminLogincount
Как любой скрипт PHP может идентифицировать это calculate
admin
Login
count
разные слова в этой строке, чтобы потом можно было проверить, если: 1-я буква 1-е слово строчная, тогда все последующие слова 1-я буква заглавная?
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()
Немного информации для тех, кто интересуется, стоит ли это того или нет, или я просто «бездельничаю» и «получаю удовольствие»:
Обязательно, чтобы имена классов были правильно названы повсюду, поскольку структура файла / папки, а также имена и имена классов должны совпадать, чтобы автозагрузчик работал без сбоев.
Хотя у меня есть проверки в самом коде ядра для проверки и обработки таких проблем, если скрипт, класс и т. Д. Не могут быть загружены (конечно), нет ничего плохого в том, что дополнительный сценарий (PHP_CodeSniffer) запускает все файлы и сообщает мне, где потенциальный вопрос может лгать.
Даже если это всего лишь для второй проверки, тем более что она обеспечивает аккуратность, правильную структуру и непрерывность кода.
Вы можете проанализировать имена функций на предмет правильного использования заглавных букв, разбив слово, где происходит переход к регистру. Для каждой части исходного имени функции найдите это подслово в словаре или файле словаря + жаргон («calc», «url», «admin» и т. Д. (Возможно, сначала проверьте жаргон)). Если какое-либо подслово терпит неудачу, то надлежащая капитализация не на месте.
Вы можете использовать Solr или ElasticSearch, чтобы разбить ваши слова на части с помощью WordDelimiterFilter в Lucene. Это создаст подслов при изменении регистра:
"PowerShot" -> "Power" "Shot""LoginURL" => "Login" "URL"
Вы можете либо вставить слова непосредственно в эти базы данных NoSQL и выполнить анализ позже, либо вы можете (по крайней мере, в ES) просто использовать фильтр токенов разделителя слов, чтобы разбить ваш запрос без фактического сохранения результатов.
https://wiki.apache.org/solr/AnalyzersTokenizersTokenFilters#solr.WordDelimiterFilterFactory
Пример:
calcAdminLogin => calc Admin Войти
calcadminlogin => calcadminlogin
Если у вас есть дополнительный словарь, который содержит такие слова, как «calc» и «admin», то имя первой функции будет разложено на 3 слова, которые будут присутствовать в словаре, поэтому верблюд верен.
Во втором примере ‘calcadminlogin’ не будет найден в словаре, поэтому верблюжий регистр неверен.
Я сделал несколько сценариев, чтобы попытаться «свободно» определить, является ли имя класса CamelCase.
Некоторые сценарии, которые я написал для моего сценария, не помогут другим, например, они тоже специфичные для моих собственных соглашений об именах (я не включил их здесь).
Так что моя настоящая коллекция сценариев делает все это стоящим, но, надеюсь, приведенные ниже более общие помогут кому-то еще.
Например, я добавляю имена классов в нижнем регистре, поэтому проверяю, является ли слово после этого префикса прописным.
Для тех (большинство людей), которые не ставят имена классов перед определенным словом, достаточно просто проверить, что первый символ строки в нижнем регистре.
Критика очень приветствуется.
Это гарантирует, что имя класса содержит только прописные или строчные буквенные буквы (Az), которые необходимы для проверок camelCase (если вы удалите этот сценарий, вам придется изменить другие сценарии, чтобы приспособиться к потенциалу не-альфа символы).
/** 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;
}
Некоторые стандарты допускают аббревиатуры и т. Д., Однако мои стандарты не допускают этого, так как это не строгий camelCase и нарушает поток чтения.
например 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 заглавных буквы, не являющихся частью 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 слов camelCase в названии класса; Найдено 5
Если возвращается слишком много ложных срабатываний (разные разработчики используют разные слова и т. Д.), То настройте текущее значение «5» вверх или вниз на ступеньку выше.
редактировать: Обновлен этот скрипт выше:
var --
), чтобыВы должны иметь отдельную проверку выше этой, чтобы проверить первое слово, которое returns
если первое слово не в нижнем регистре.