У меня есть функция, которая используется во всем моем коде. Функция ожидает, что переданный параметр является положительным целым числом. Поскольку PHP свободно набирается, тип данных неважен. Но важно, чтобы в нем не было ничего, кроме цифр. В настоящее время я использую регулярное выражение для проверки значения перед продолжением.
Вот упрощенная версия моего кода:
function do_something($company_id) { if (preg_match('/\D/', $company_id)) exit('Invalid parameter'); //do several things that expect $company_id to be an integer }
Я исхожу из фона Perl и часто часто встречаюсь для регулярных выражений. Однако я знаю, что их использование противоречиво.
Я рассматривал использование intval()
или (int)
и принуждение $company_id
к целому числу. Однако я мог бы получить некоторые неожиданные значения, и я хочу, чтобы он быстро провалился .
Другой вариант:
if (!ctype_digit((string) $company_id)) exit('Invalid parameter');
Является ли этот сценарий действительным использованием регулярных выражений? Один из способов предпочтительнее другого? Если да, то почему? Есть ли какие-то ошибки, которые я не рассматривал?
Первоначальный вопрос заключается в проверке значения неизвестного типа данных и отбрасывании всех значений, кроме тех, которые содержат только цифры . Кажется, существует только два пути для достижения этого желаемого результата.
Если цель состоит в том, чтобы быстро выйти из строя , нужно проверить недопустимые значения, а затем выполнить сбой, а не проверять допустимые значения и обернуть весь код в блок if
.
if (preg_match('/\D/', $company_id)) exit('Invalid parameter');
Использование regex
для отказа, если совпадают цифры. Con: двигатель regex имеет верхние
if (!ctype_digit((string) $company_id)) exit('Invalid parameter');
Использование ctype_digit
для отказа, если FALSE. Con: значение должно быть передано в строку, которая является (небольшим) дополнительным шагом
Вы должны ctype_digit
значение для строки, потому что ctype_digit
ожидает строку, и PHP не будет ctype_digit
параметр в строку для вас. Если вы передадите целое число в ctype_digit
, вы получите неожиданные результаты.
Это документированное поведение. Например:
ctype_digit('42'); // true ctype_digit(42); // false (ASCII 42 is the * character)
Из-за накладных расходов на двигатель регулярного выражения вариант второй вариант, вероятно, лучший вариант. Однако, беспокоиться о различии между этими двумя вариантами может оказаться в категории преждевременной оптимизации.
Примечание. Существует также функциональная разница между двумя приведенными выше опциями. Первый вариант рассматривает NULL
и пустые строки как допустимые значения, второй – нет (с PHP 5.1.0). Это может сделать один метод более желательным, чем другой. Чтобы функция опции regex
такой же, как версия ctype_digit
, используйте ее вместо этого.
if (!preg_match('/^\d+$/', $company_id)) exit('Invalid parameter');
Примечание: «начало строк» и «конец строки» $
anchors в вышеупомянутом regex
очень важны. В противном случае abc123def
будет считаться действительным.
Существуют и другие методы, которые были предложены здесь и в других вопросах, которые не достигнут заявленных целей , но я думаю, что важно упомянуть их и объяснить, почему они не будут работать, поскольку это может помочь кому-то другому.
is_numeric
позволяет экспоненциальные части, поплавки и шестнадцатеричные значения
is_int
проверяет тип данных, а не значение, которое не полезно для проверки, если '1'
считается действительным. И ввод формы всегда является строкой. Если вы не знаете, откуда это значение, вы не можете быть уверены в типе данных.
filter_var
с FILTER_VALIDATE_INT
допускает отрицательные целые числа и значения, такие как 1.0
. Это кажется лучшей функцией для фактической проверки целого числа независимо от типа данных. Но не работает, если вы хотите только цифры. Примечание. Важно проверить идентификацию FALSE
а не правду / ложь, если 0
следует считать допустимым значением.
Как насчет filter_var
+ FILTER_VALIDATE_INT
?
if (FALSE === ($id = filter_var($_GET['id'], FILTER_VALIDATE_INT))) { // $_GET['id'] does not look like a valid int } else { // $id is a int because $_GET['id'] looks like a valid int }
Кроме того, он имеет параметры min_range / max_range.
Основная идея этой функции более или менее эквивалентна:
function validate_int($string) { if (!ctype_digit($string)) { return FALSE; } else { return intval($string); } }
Кроме того, если вы ожидаете целое число, вы можете использовать is_int
. К сожалению, тип hinting ограничен объектами и массивом.
Оба метода передадут переменную в строку. preg_match
не принимает объект типа integer, поэтому он будет передан в строку, однажды переданную функции. ctype_digit
, безусловно, является лучшим решением в этом случае.