PHP错误抑制符(@)导致引用传参失败Bug的分析


Posted in PHP onMay 02, 2011

看下面的例子:

<?php 
$array = array(1,2,3); 
function add (&$arr) { 
$arr[] = 4; 
} 
add(@$array); 
print_r($array); 
/** 
此时, $array没有改变, 输出: 
Array 
( 
[0] => 1 
[1] => 2 
[2] => 3 
) 
*/ 
add($array); 
print_r($array); 
/** 
不使用错误抑制的情况下, 输出正常: 
Array 
( 
[0] => 1 
[1] => 2 
[2] => 3 
[3] => 4 
) 
*/ 
?>

这个问题, 我之前没有遇到过, 所以首先去找找相关资料, 看看有没有现成的答案, Goolge了一番, 发现虽然有人已经向PHP报了类似的Bug:http://bugs.php.net/bug.php?id=47623, 但PHP官方还没有解决, 也没有给出答复.

没办法, 只能自己分析了, 之前我曾经在文章中介绍过错误抑制符的原理( 深入理解PHP原理之错误抑制与内嵌HTML), 从原理上来说, 错误抑制只是修改了error_reporting的level, 按理来说不会影响到上下文之间的函数调用的机制. 只能通过实地试验了.

经过gdb跟踪, 发现在使用了错误移植符以后, 函数调用前的传参opcode不同:

//没有使用错误抑制符的时候 
OPCODE = SEND_REF 
//使用了错误抑制符号以后 
OPCODE = SEND_VAR_NO_RE

问题初步定位了, 但是造成这种差异的原因又是什么呢?

既然OPCODE不同, 那么肯定是在语法分析的阶段, 走了不同的分支了, 想到这一层, 问题也就好定位了,

原来, PHP语法分析阶段, 把形如 “@”+expr的条目, 规约成了expr_without_variable, 而这种节点的意义就是没有变量的值, 也就是字面值, 我们都知道字面值是不能传递引用的(因为它不是变量), 所以, 就会导致这种差异.

具体过程如下:
1. 语法分析阶段:

expr_without_variable: 
//...有省略 
| '@' { zend_do_begin_silence(&$1 TSRMLS_CC); } 
expr { zend_do_end_silence(&$1 TSRMLS_CC); $$ = $3; } 
//此处走了ZEND_SEND_VAL分支 
non_empty_function_call_parameter_list: 
expr_without_variable { ....} //错误的走了这个分支 
| variable {..... } //正常情况

所以导致在编译期间, 生成了不同的OPCODE, 也导致了问题的表象.
最后, 我已经把原因在PHP的这个bug页做了说明, 有兴趣的可以去看看我的烂英语水平. 最后谢谢cici网友提供的这个有趣的问题.
PHP 相关文章推荐
IStream与TStream之间的相互转换
Aug 01 PHP
完美实现GIF动画缩略图的php代码
Jan 02 PHP
php array_walk() 数组函数
Jul 12 PHP
php实现查询百度google收录情况(示例代码)
Aug 02 PHP
PHP根据传来的16进制颜色代码自动改变背景颜色
Jun 13 PHP
分享一个Laravel好用的Cache宏
Mar 02 PHP
Smarty高级应用之缓存操作技巧分析
May 14 PHP
总结PHP中DateTime的常用方法
Aug 11 PHP
Zend Framework动作控制器用法示例
Dec 09 PHP
PHP静态成员变量
Feb 14 PHP
PHP getName()函数讲解
Feb 03 PHP
php实现的生成排列算法示例
Jul 25 PHP
一些PHP Coding Tips(php小技巧)[2011/04/02最后更新]
May 02 #PHP
PHP中使用gettext来支持多语言的方法
May 02 #PHP
php中神奇的fastcgi_finish_request
May 02 #PHP
PHP开发不能违背的安全规则 过滤用户输入
May 01 #PHP
PHP 调试工具Debug Tools
Apr 30 #PHP
php debug 安装技巧
Apr 30 #PHP
vs中通过剪切板循环来循环粘贴不同内容
Apr 30 #PHP
You might like
cmd下运行php脚本
2008/11/25 PHP
PHP中实现中文字符进制转换原理分析
2011/12/06 PHP
smarty模板中使用get、post、request、cookies、session变量的方法
2014/04/24 PHP
PHP易混淆知识整理笔记
2015/09/24 PHP
php 流程控制switch的简单实例
2016/06/07 PHP
php加密解密字符串示例
2016/10/13 PHP
jQuery动态设置form表单的enctype值(实现代码)
2013/07/04 Javascript
XMLHttpRequest处理xml格式的返回数据(示例代码)
2013/11/21 Javascript
中止javascript执行的方法
2014/02/14 Javascript
jQuery简单图表peity.js使用示例
2014/05/02 Javascript
JavaScript实现的简单烟花特效代码
2015/10/20 Javascript
JavaScript代码判断点击第几个按钮
2015/12/13 Javascript
基于JavaScript代码实现自动生成表格
2016/06/15 Javascript
web前端vue之CSS过渡效果示例
2018/01/10 Javascript
layui table设置前台过滤转义等方法
2018/08/17 Javascript
layui 弹出删除确认界面的实例
2019/09/06 Javascript
借助云开发实现小程序短信验证码的发送
2020/01/06 Javascript
[27:02]2014 DOTA2国际邀请赛中国区预选赛 5 23 CIS VS LGD第三场
2014/05/24 DOTA
[00:32]2018DOTA2亚洲邀请赛VG出场
2018/04/03 DOTA
Python模拟登录12306的方法
2014/12/30 Python
python DataFrame获取行数、列数、索引及第几行第几列的值方法
2018/04/08 Python
对Python发送带header的http请求方法详解
2019/01/02 Python
对Python生成器、装饰器、递归的使用详解
2019/07/19 Python
Python做图像处理及视频音频文件分离和合成功能
2020/11/24 Python
scrapy实践之翻页爬取的实现
2021/01/05 Python
全球速卖通西班牙站:AliExpress西班牙
2017/10/30 全球购物
Farfetch澳大利亚官网:Farfetch Australia
2020/04/26 全球购物
FragranceNet中文网:北美健康美容线上零售商
2020/08/26 全球购物
爱护公物演讲稿
2014/09/09 职场文书
超市督导岗位职责
2015/04/10 职场文书
英语导游欢迎词
2015/09/30 职场文书
会计手工模拟做账心得体会
2016/01/22 职场文书
母婴行业实体、电商模式全面解析
2019/08/01 职场文书
javaScript Array api梳理
2021/03/31 Javascript
python爬取网页版QQ空间,生成各类图表
2021/06/02 Python
JS前端canvas交互实现拖拽旋转及缩放示例
2022/08/05 Javascript