Проверка того, что значение содержит только цифры, регулярное выражение или нет?

У меня есть функция, которая используется во всем моем коде. Функция ожидает, что переданный параметр является положительным целым числом. Поскольку 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 .

Вариант 1 из вопроса

 if (preg_match('/\D/', $company_id)) exit('Invalid parameter'); 

Использование regex для отказа, если совпадают цифры. Con: двигатель regex имеет верхние

Вариант 2 из вопроса

 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) 

Разница между Вариантами 1 и 2

Из-за накладных расходов на двигатель регулярного выражения вариант второй вариант, вероятно, лучший вариант. Однако, беспокоиться о различии между этими двумя вариантами может оказаться в категории преждевременной оптимизации.

Примечание. Существует также функциональная разница между двумя приведенными выше опциями. Первый вариант рассматривает 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 , безусловно, является лучшим решением в этом случае.