检查一个值是否只包含数字,使用正则表达式还是不使用?

6

我有一个在我的代码中经常使用的函数。该函数期望传递的参数为正整数。由于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');

这个场景是否可以使用正则表达式?有没有一种方法更好?如果是,为什么?我是否考虑到了任何陷阱?


ctype_digit 函数有什么问题吗? - Michael
我的看法是ctype_digit唯一的缺点就是它必须先转换为一个字符串。然而,我发现 regex 更易于阅读,并且我习惯使用它。我正在尝试确定是否有充分的理由进行切换。 - toxalot
3个回答

8

目标

原始问题是关于验证未知数据类型的值并丢弃除了只包含数字以外的所有值。似乎只有两种方法可以实现这一期望结果。

如果目标是快速失败,则应检查无效值,然后失败,而不是检查有效值并将所有代码包装在if块中。

选项1来自问题

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

使用 regex 来匹配非数字并失败。缺点是正则表达式引擎会增加开销。

问题中的选项 2

if (!ctype_digit((string) $company_id)) exit('Invalid parameter');

使用ctype_digit来判断是否为FALSE。缺点是需要将值转换为字符串,这是(一个小的)额外步骤。
您必须将值转换为字符串,因为ctype_digit期望一个字符串,而PHP不会为您将参数转换为字符串。如果您将整数传递给ctype_digit,则会得到意外的结果。
这是已记录的行为。例如:
ctype_digit('42'); // true
ctype_digit(42); // false (ASCII 42 is the * character)

选项1和选项2之间的区别

由于正则表达式引擎的开销,选项2可能是最好的选择。但是,过分关注这两个选项之间的差异可能会陷入过早优化的类别。

注意: 上述两个选项之间也存在功能上的差异。第一个选项将NULL和空字符串视为有效值,而第二个选项不会(从PHP 5.1.0开始)。这可能使其中一种方法比另一种更可取。要使regex选项与ctype_digit版本的功能相同,请改用以下内容。

if (!preg_match('/^\d+$/', $company_id)) exit('Invalid parameter');

注意:上述regex中的“字符串开始”^和“字符串结束”$锚非常重要。否则,abc123def将被视为有效。

其他选项

这里和其他问题中提出了其他方法,但它们无法实现所述目标,但我认为提到它们并解释为什么它们不起作用可能会帮助其他人。

  • is_numeric允许指数部分、浮点数和十六进制值。

  • is_int检查数据类型而不是值,这对于验证如果'1'应该被视为有效是没有用的。表单输入始终是一个字符串。如果您不确定值来自何处,则无法确定数据类型。

  • filter_varFILTER_VALIDATE_INT允许负整数和诸如1.0之类的值。这似乎是实际验证整数的最佳函数,无论数据类型如何。但如果你只想要数字,它就不起作用了。注意:如果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。不幸的是,类型提示仅限于对象和数组。


0

这两种方法都会将变量强制转换为字符串。preg_match不接受整数类型的主题,因此一旦传递给函数,它将被强制转换为字符串。ctype_digit在这种情况下绝对是最佳选择。


两种方法都会将变量转换为字符串。这是正确的...除了preg_match,PHP会自动转换。而对于ctype_digit,您需要自己完成转换。 - toxalot

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接