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

tox*_*lot 6 php regex validation

我有一个在我的代码中使用的函数.该函数期望传递的参数是正整数.由于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
}
Run Code Online (Sandbox Code Playgroud)

我来自Perl背景,往往会经常使用正则表达式.但是,我知道他们的用法是有争议的.

我认为使用intval()(int)迫使 $company_id是一个整数.但是,我最终会得到一些意想不到的值,我希望它快速失败.

另一种选择是:

if (!ctype_digit((string) $company_id)) exit('Invalid parameter');
Run Code Online (Sandbox Code Playgroud)

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

tox*_*lot 6

目标

最初的问题是验证未知数据类型的值并丢弃除除数字之外的所有值.似乎只有两种方法可以实现这种期望的结果.

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

问题的备选方案1

if (preg_match('/\D/', $company_id)) exit('Invalid parameter');
Run Code Online (Sandbox Code Playgroud)

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

问题的备选方案2

if (!ctype_digit((string) $company_id)) exit('Invalid parameter');
Run Code Online (Sandbox Code Playgroud)

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

您必须将值转换为字符串,因为ctype_digit需要一个字符串,PHP不会将参数转换为字符串.如果传递一个整数ctype_digit,则会得到意外的结果.

这是记录在案的行为.例如:

ctype_digit('42'); // true
ctype_digit(42); // false (ASCII 42 is the * character)
Run Code Online (Sandbox Code Playgroud)

选项1和2之间的差异

由于正则表达式引擎的开销,选项二可能是最好的选择.但是,担心这两个选项之间的差异可能属于过早的优化类别.

注意:上述两个选项之间也存在功能差异.第一个选项将NULL空字符串视为有效值,第二个选项不考虑(从PHP 5.1.0开始).这可能使一种方法比另一种方法更令人满意.要使regex选项功能与ctype_digit版本相同,请改用它.

if (!preg_match('/^\d+$/', $company_id)) exit('Invalid parameter');
Run Code Online (Sandbox Code Playgroud)

注意:上面的'字符串的开头' ^和'字符串的结尾' $锚点regex非常重要.否则,abc123def将被视为有效.

其他选择

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

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

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

  • filter_varFILTER_VALIDATE_INT允许负整数和值,诸如1.0.这似乎是实际验证整数的最佳函数,无论数据类型如何.但如果你想要数字,则不起作用.注意:如果要将其视为有效值,则检查FALSE 身份而不仅仅是真实/虚假0是很重要的.