51CTO诚邀您9月23号和秒拍/国美/美团云专家一路聊智能CDN的优化之路,抓紧时光哦!
碰到的问题
比来碰到一个PHP大年夜整数的问题,问题代码是如许的
- $shopId = 17978812896666957068;
- var_dump($shopId);
1、查看opcode
膳绫擎的代码输出,会把$shopId转换成float类型,且应用了科学计数法来表示,输出如下:
- float(1.7978812896667E+19)
但在法度榜样里须要的是完全的数字作为查找数据的参数,所以须要用的是完全的数字,当时认为只是因为数据被转换成科学计数法了,于是想到的解决筹划是强迫让它不应用科学计数法表示:
- $shopId= number_format(17978812896666957068);
- var_dump($shopId);
这时刻奇怪的工作出现了,输出的是:
- 17978812896666957824
当时没有细心看,比较了前十位就没有持续往下看,所以认为问题解决了,比及真正根据ID去找数据的时刻才发明数据查不出来,这时刻才发明是数据转换缺点了。
这里应用number_format掉败的原因在后面会讲到,当时就想到将本来的数据转成字符串的,然则应用了以下办法仍然不可
- $shopId= strval(17978812896666957068);
- var_dump($shopId);
- $shopId = 17978812896666957068 . ‘’;
- var_dump($shopId);
输出的结不雅都是
在PHP内部有一个函数用来快速的返回特定opcode对应的opcode处理函数指针:zend_vm_get_opcode_handler()函数:
- float(1.7978812896667E+19)
最后只有下面这种筹划是可行的:
- $shopId = ‘17978812896666957068’;
- var_dump($shopId);
- // 输出
- //string(20) "17978812896666957068"
众所周知,PHP是一门解释型说话,所以当时就大年夜胆地猜测PHP是在编译时代就将数字的字面量常量转换成float类型,并用科学计数法表示。但仅仅猜测不克不及知足本身的好奇心,想要看到真正实现代码才愿意信赖。于是就慢慢分析、摸索,直到找到背后的实现。
刚开端根据这个问题直接上彀搜“PHP大年夜整数解析过程”,并没有搜到谜底,是以只能本身去追查。一开端对PHP的履行过程不熟悉,出发点就只能是一步一步地调试,然后
示例代码:
- // test.php
- $var = 17978812896666957068;
- var_dump($var);
追查过程
经由过程vld查看PHP履行代码的opcode,可以看到,赋值的是一个ASSIGN的opcode操作
接下来就想看看ASSIGN是在哪里履行的。
2、gdb调试
总结
2-1、用list查看竽暌剐什么处所可以进行断点
2-2、临时没有头绪,在1186断点尝尝
结不雅法度榜样走到sapi/cli/php_cli.c文件的1200行了,按n赓续下一步履行,一向到这里就走到了法度榜样输出结不雅了:
猜测最有可能的是在zendparse、zend_compile_top_stmt这两个阶段完成转换,因为这个两个阶段做的工作就是将PHP代码转换成opcode数组。
推荐阅读
51CTO诚邀您9月23号和秒拍/国美/美团云专家一路聊智能CDN的优化之路,抓紧时光哦! BIOS,英文"Basic Input Output System"的缩略词,直译过来后中文名称就是"根本输入输出体系",这些专业>>>详细阅读
本文标题:自上而下,逐步揭开PHP解析大整数的面纱
地址:http://www.17bianji.com/lsqh/37473.html
1/2 1