为啥 is_numeric() 在传递看似数字的字符串时返回 false?
Posted
技术标签:
【中文标题】为啥 is_numeric() 在传递看似数字的字符串时返回 false?【英文标题】:Why does is_numeric() return false when passed a seemingly numeric string?为什么 is_numeric() 在传递看似数字的字符串时返回 false? 【发布时间】:2021-03-06 17:39:24 【问题描述】:我正在尝试理解 php 中的数字字符串。 我有以下代码:
var_dump(5 * "10 abc");
var_dump(is_numeric("10 abc"));
这给了我输出:
int(50)
bool(false)
这让我感到困惑,因为字符串 "10 abc" 似乎在第一个表达式中被解释为数字字符串(因此 int(50) 输出并且没有关于使用非数字值的警告),但是当运行 is_numeric() 函数时,它返回 false,表明它实际上不是数字字符串。
我花了一些时间查看文档以了解此行为,但找不到任何具体答案,有人可以帮助解释导致此行为的原因吗?
我知道 PHP 8.0.0 对数字字符串进行了一些更改,但这是我现在正在尝试理解的 PHP 7.1.33。
【问题讨论】:
在第一个表达式中,“10 abc”转换为 int,得到10
。而且这和is_numeric
check没有关系。
我建议不要使用is_numeric()
和empty()
。 IMO 两者都非常“松软”。 F.e. empty('0')
是真的,这是 IMO 错误的,因为我有一个带字符的字符串。关于is_numeric
,如果您期望一个int ((int)$val
),我建议转换为int。然后,您还可以检查原始值是否符合 int-casted 值。
顺便说一句:有更好的功能 - ctype_*
功能。在你的情况下ctype_digit
.
【参考方案1】:
“Saner numeric string”RFC 的 RFC 作者,在此处被 PHP 8.0 接受。
"10 abc"
不是数字字符串,而是前导数字字符串,这意味着字符串的开头看起来像数字但不是数字因为在字符串中的某个点存在乱码(这包括空格)。
因为is_numeric()
根据 PHP 的定义检查一个值是否被视为数字(在 PHP 8.0 之前,这意味着前导空格后跟一个 + 或 - 号以及任何整数、普通十进制数或指数表示法),它将在仅被视为前导数字的字符串上返回 false
。
但是,算术运算会尝试将其操作数转换为适当的数字类型(int 或 float),因此 "10 abc"
会转换为 10
,因为 PHP 会将前导数字字符串转换为其前导数值。
更多“有趣”的细节和边缘案例可以在technical background section of the PHP RFC 中找到。
【讨论】:
【参考方案2】:我认为理解您描述的行为的最简单方法是,仅仅因为字符串不是数字,并不意味着它不能被强制或视为数字强>。
你的第一行代码
var_dump(5 * "10 abc");
将字符串视为数字,一旦遇到无效字符,它就会忽略之后的所有内容。
你的另一行代码
var_dump(is_numeric("10 abc"));
实际上表现得更聪明,并且像人类一样问自己,我们在这里处理的是数字字符串吗?答案是否定的(因为同样的无效字符)。
【讨论】:
以上是关于为啥 is_numeric() 在传递看似数字的字符串时返回 false?的主要内容,如果未能解决你的问题,请参考以下文章