我有一个在我的代码中使用的函数。该函数期望传递的参数是正整数。由于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');
这种情况是否有效使用正则表达式?一种方式优于另一种方式吗?如果是这样,为什么?有没有我没考虑过的问题?
答案 0 :(得分:5)
最初的问题是验证未知数据类型的值并丢弃除除数字以外的所有值以外的所有值。似乎只有两种方法可以达到预期的效果。
如果目标是快速失败,则需要检查无效值,然后失败而不是检查有效值并且必须将所有代码包装在if
块中。
if (preg_match('/\D/', $company_id)) exit('Invalid parameter');
如果匹配非数字,则使用regex
失败。 Con:正则表达式引擎有开销
if (!ctype_digit((string) $company_id)) exit('Invalid parameter');
如果为FALSE,则使用ctype_digit
失败。 Con:值必须转换为字符串,这是一个(小)额外步骤
您必须将值强制转换为字符串,因为ctype_digit
需要一个字符串,PHP不会将参数转换为字符串。如果将整数传递给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');
注意:以上^
中的'字符串'$
和'字符串结尾'regex
锚定非常重要。否则,abc123def
将被视为有效。
此处已提出其他方法以及无法实现既定目标的其他问题,但我认为提及它们并解释为什么它们无法正常工作非常重要可能会帮助别人。
is_numeric
允许指数部分,浮点数和十六进制值
is_int
检查数据类型而不是值,如果'1'
被认为有效,则该值对验证无效。表单输入始终是一个字符串。如果您不确定值的来源,则无法确定数据类型。
filter_var
的 FILTER_VALIDATE_INT
允许使用1.0
等负整数和值。这似乎是实际验证整数的最佳函数,无论数据类型如何。但如果您只想 数字,则无效。 注意:如果要将FALSE
视为有效值,请务必检查0
身份,而不仅仅是truthy / falsey。
答案 1 :(得分: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
。不幸的是,类型提示仅限于objets和数组。
答案 2 :(得分:0)
两种方法都会将变量转换为字符串。 preg_match
不接受整数类型的主题,因此一旦传递给函数,它将被转换为字符串。在这种情况下,ctype_digit
绝对是最佳解决方案。