看群里在讨论PHP大整形,我也来做个测试记录下;
测试DEMO:
1 |
|
结果是采用科学计数法把$bigInt转换成了double型
1 | double(1.9897654567895E+19) |
思考:
难道是在编译期间将整形转成double了吗??然后再转成科学计数法??
还是用gdb调试下看看吧,通过断点获得如下opcode:
1 | (gdb) p *(op_array.opcodes)@40 |
大致了解opcode执行过程:
1 | 101 'e', extension statement |
简化如下:
1 | 38(ASSIGN) => 》61(通过名称调用函数) =>》117(未知)=>》60(函数调用)=>62(函数返回) |
dbg调试到这里,并没有发现有跟转换double相关的信息,继续打印op_array看看是否还有其他信息?
1 | $17 = { |
能看出literals是个地址信息,继续打印:发现其中的一段
1 | { |
看到结果dval = 1.9897654567894569e+19,难道execute之前就已经转换了???
op_array里面再也找不出对应的信息了,我决定重新开始dbg,调用栈如下:
1 | bt |
终于在 zend_language_scanner 发现了相关代码:
细看这两行调用栈:
1 | #1 0x000000000081e9e2 in zend_strtod (s00=<optimized out>, se=se@entry=0x7fffffffa0a8) at /usr/local/src/php-7.2.4/Zend/zend_strtod.c:3037 |
源码打开 Zend/zend_language_scanner.l:1668:
1 | <ST_IN_SCRIPTING>{LNUM} { |
常量地址:zend/zend_long.h
1 |
通过前后对比,再细看1668行代码:
1 | ZVAL_DOUBLE(zendlval, zend_strtod(yytext, (const char **)&end)); |
通过阅读代码不难发现:
zend引擎在对数字用lex_scan分析的时候,是先判断数字的长度,
如果有可能溢出,先将其转成LONG型保存,如果溢出,则通过zend_strtod转换成double类型,再用double类型的zval结构体存储;