var_dump(0…9)输出什么?


风雪之隅

一个问题, var_dump(1…9)输出什么?

动手验证下:


php -r “var_dump(1…9)”;
string(4) “10.9”

输出10.9, 乍一看,很奇怪是不是? 为什么呢?

这里教大家, 如果看到一段代码感觉输出有点怪, 第一反应是看下这段代码生成的opcodes是啥,用phpdbg分析下(一般为了防止opcache的影响,会传递-n):

phpdbg -n -p /tmp/1.php
function name: (null)
L1-35 {main}() /tmp/1.php – 0x7f56d1a63460 + 4 ops
L2 #0 INIT_FCALL<1> 96 “var_dump”
L2 #1 SEND_VAL “10.9” 1
L2 #2 DO_ICALL
L35 #3 RETURN<-1> 1

所以这么看来,早在生成opcode之前,1…9就变成了常量10.9,考虑到这是字面量,我们现在去看看zend_language_scanner.l, 找到这么一行:

DNUM ({LNUM}?”.”{LNUM})|({LNUM}”.”{LNUM}?)

这个是词法分析定义的浮点数的格式,到这里也就恍然大悟了:
1…9 会被依次接受为: 1. (浮点数1), 然后是 . (字符串连接符号) 然后是.9(浮点数0.9)

所以在编译阶段就会直接生成 “1” . “0.9” => 字符串的字面量”10.9”

好了,到这里,“谜题”就解释清楚了。

最后,这个也不仅仅是PHP会这么定义了,几乎所有的语言都会定义这种缩写浮点数都形式. C语言中有的时候我们为了输入一个浮点型的整形,就可以采用比如 1. 来告诉编译器这是个浮点数.

只不过,刚好在PHP中.号还有另外一层含义就是字符串连接,导致了这个看起来很困惑的结果, 🙂