使用PHP 5.3.5。不确定这在其他版本上是如何工作的。
我对使用包含数字的字符串感到困惑,例如'0x4B0'
或'1.2e3'
。PHP处理这些字符串的方式在我看来似乎不一致。难道只有我一个人吗?还是一个bug?或者未记录的功能?还是我只是在文档中漏掉了一些神奇的句子?
<?php
echo $str = '0x4B0', PHP_EOL;
echo "is_numeric() -> ", var_dump(is_numeric($str)); // bool(true)
echo "*1 -> ", var_dump($str * 1); // int(1200)
echo "(int) -> ", var_dump((int)$str); // int(0)
echo "(float) -> ", var_dump((float)$str); // float(0)
echo PHP_EOL;
echo $str = '1.2e3', PHP_EOL;
echo "is_numeric() -> ", var_dump(is_numeric($str)); // bool(true)
echo "*1 -> ", var_dump($str * 1); // float(1200)
echo "(int) -> ", var_dump((int)$str); // int(1)
echo "(float) -> ", var_dump((float)$str); // float(1200)
echo PHP_EOL;
在这两种情况下,is_numeric()
都返回true
。此外,在这两种情况下,$str * 1
都解析字符串并返回有效数字(一种情况下为整数,另一种情况为浮点)。
用(int)$str
和(float)$str
铸造会产生意想不到的结果。
(int)$str
在任何情况下都只能解析数字,前面有可选的"+"或"-"(float)$str
更高级,可以解析类似^[+-]?'d*('.'d*)?(e[+-]?'d*)?
的东西,即可选的"+"或"-",后面跟着可选数字,后面跟着带可选数字的可选小数点,后面跟着由"e"和可选的"+"或"-"组成的可选指数,后面跟着选择数字。但是在十六进制数据上失败
相关文档:
- is_numeric()-声明"也允许使用十六进制表示法(0xFF),但只允许不包含符号、小数和指数部分"。若用于测试字符串是否包含数字数据的函数返回true,我希望PHP能够将这样的字符串转换为数字。这似乎适用于
$str * 1
,但不适用于选角。为什么 - 转换为integer-表示"在大多数情况下不需要强制转换,因为如果运算符、函数或控制结构需要整数参数,则会自动转换值"。在这样的语句之后,我希望
$s * 10
和(int)$s * 10
表达式以相同的方式工作,并返回相同的结果。不过,如示例所示,这些表达式的求值方式不同 - 字符串转换为数字-表示"有效的数字数据是一个可选符号,后跟一个或多个数字(可选包含小数点),后跟可选指数"。"Exponent"是"e"或"e",后面跟数字,例如
1.2e3
是有效的数字数据。未提及符号("+"或"-")。它没有提到十六进制值。这与is_numeric()
中使用的"数字数据"的定义相冲突。然后,建议"有关此转换的更多信息,请参阅strtod(3)的Unix手册页",man strtod
描述了其他数值(包括HEX表示法)。那么,在阅读了这篇文章之后,十六进制数据应该是有效的还是无效的数字数据
所以。。。
- 当字符串用作数字时,
is_numeric()
和PHP处理字符串的方式之间是否存在(或者应该存在)任何关系 - 当
$s
是0x4B0
还是1.2e3
时,为什么(int)$s
、(float)$s
和$s * 1
的工作方式不同,即给出完全不同的结果 - 如果字符串被写成
0x4B0
或1.2e3
,有没有办法将其转换为数字并保持其值?floatval()
根本不适用于HEX,intval()
需要将$base
设置为16
才能使用HEX,使用(int)$str
和(float)$str
的类型转换有时有效,有时不起作用,因此这些都不是有效的选项。我也不考虑$n *= 1;
,因为它看起来更像是数据操作,而不是转换。在这种情况下也不考虑自写函数,因为我正在寻找本机解决方案
直接转换(int)$str
和(float)$str
的工作方式并没有什么不同:它们都可以从字符串中读取尽可能多的字符,并将其解释为各自类型的数字。
对于"0x4B0",int转换读取"0"(OK),然后读取"x"并停止,因为它无法将"x"转换为整数。浮点转换也是如此。
对于"1.2e3",int转换读取"1"(OK),然后读取"."并停止。浮点转换将整个字符串识别为有效的浮点表示法。
像$str * 1
这样的表达式的自动类型识别比显式类型转换更灵活。显式强制转换本质上要求整数和浮点为printf
中%i
和%f
生成的格式。
不过,也许您可以使用intval和floatval,而不是显式转换为int,以获得更大的灵活性。
最后,您的问题"十六进制数据应该是有效的还是无效的数字数据?"很尴尬。没有所谓的"十六进制数据"。十六进制只是一个基数可以使用类似"4B0"的字符串,并使用[对不起,那是BS。PHP中没有strtoul
等将其解析为任何2到36之间的数字基数中的整数。strtoul
。但intval
具有等效的功能,请参阅上文。]
intval
使用strtol,当base
参数为零时,它可以识别oct/hex前缀,因此
var_dump(intval('0xef')); // int(0)
var_dump(intval('0xff', 0)); // int(255)
Is_numeric()和PHP将字符串用作数字时处理字符串的方式之间是否存在(或者更确切地说,是否应该存在)任何关系?
PHP中没有名为numeric的数据类型,is_numeric()
函数更像是对PHP可以解释为数字的东西的测试。
就这种数字解释而言,在值前面添加+
实际上会使PHP将其转换为数字:
$int = +'0x4B0';
$float = +'1.2e3';
您可以在字符串手册中找到解释,请参阅字符串转换为数字一节。
由于它是由一个运算符触发的,所以我认为PHP中不需要有一个函数来做同样的事情。这将是多余的。
PHP内部使用一个名为zendi_convert_scalar_to_number
的函数作为加法运算符(假定为+
),该运算符将使用is_numeric_string
来获取数字。
当与字符串一起使用时,is_numeric()
会在内部调用完全相同的函数。
因此,要触发本机转换函数,我只需要使用+
运算符。这将确保您将返回数字伪类型(int或float)。
参考:/Zend/Zend_operators.c/ext/standard/type.c