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()or(int)强制 $company_id为整数。但是,我最终可能会得到一些意想不到的值,我希望它快速失败

另一种选择是:

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

这种情况是正则表达式的有效使用吗?一种方式优于另一种方式吗?如果是这样,为什么?有没有我没有考虑过的问题?

4

3 回答 3

7

目标

最初的问题是关于验证未知数据类型的值并丢弃所有值,除了那些只包含数字的值。似乎只有两种方法可以达到这个预期的结果。

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

问题中的选项 1

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

regex如果匹配非数字,则使用失败。缺点:正则表达式引擎有开销

问题中的选项 2

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

如果为 FALSE,则使用ctype_digit失败。缺点:必须将值转换为字符串,这是一个(小)额外步骤

您必须将值转换为字符串,因为ctype_digit需要一个字符串,而 PHP 不会为您将参数转换为字符串。如果你将一个整数传递给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');

注意:上面的'start of string'^和'end of string'$锚点regex非常重要。否则,abc123def将被视为有效。

其他选项

这里和其他问题中还提出了其他方法,这些方法无法实现既定目标,但我认为重要的是要提及它们并解释它们为什么不起作用,因为它可能对其他人有帮助。

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

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

  • filter_varwithFILTER_VALIDATE_INT允许负整数和值,例如1.0. 无论数据类型如何,这似乎都是实际验证整数的最佳函数。但是如果你只想要数字就行不通了。注意:重要的是要检查FALSE 身份,而不仅仅是真/假是否0被视为有效值。

于 2012-12-08T20:15:45.273 回答
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. 不幸的是,类型提示仅限于对象和数组。

于 2012-12-08T17:46:49.610 回答
0

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

于 2012-12-09T05:15:35.500 回答