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 相关文章推荐
PHP parse_url 一个好用的函数
Oct 03 PHP
PHP基础学习小结
Apr 17 PHP
php下通过curl抓取yahoo boss 搜索结果的实现代码
Jun 10 PHP
php仿QQ验证码的实例分析
Jul 01 PHP
php有道翻译api调用方法实例
Dec 22 PHP
php数组去除空值函数分享
Feb 02 PHP
php实现的IMEI限制的短信验证码发送类
May 05 PHP
PHP通过串口实现发送短信
Jul 08 PHP
Zend Framework教程之Application和Bootstrap用法详解
Mar 10 PHP
php+jQuery+Ajax简单实现页面异步刷新
Aug 08 PHP
PHP读MYSQL中文乱码的快速解决方法
Oct 01 PHP
阿里云的WindowsServer2016上部署php+apache
Jul 17 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
PHP array 的加法操作代码
2010/07/24 PHP
Laravel学习教程之View模块详解
2017/09/18 PHP
发两个小东西,ASP/PHP 学习工具。 用JavaScript写的
2007/04/12 Javascript
简单的无缝滚动程序-仅几行代码
2007/05/08 Javascript
各种常用的JS函数整理
2013/10/25 Javascript
js倒计时小程序
2013/11/05 Javascript
js监听滚动条滚动事件使得某个标签内容始终位于同一位置
2014/01/24 Javascript
jQuery中:empty选择器用法实例
2014/12/30 Javascript
js实现感应鼠标图片透明度变化的方法
2015/02/20 Javascript
Javascript进制转换实例分析
2015/05/14 Javascript
js行号显示的文本框实现效果(兼容多种浏览器 )
2015/10/23 Javascript
js前端实现多图图片上传预览的两个方法(推荐)
2016/11/18 Javascript
微信小程序实战之运维小项目
2017/01/17 Javascript
jquery插件canvaspercent.js实现百分比圆饼效果
2017/07/18 jQuery
webpack vue项目开发环境局域网访问方法
2018/03/20 Javascript
微信小程序使用wxParse解析html的方法示例
2019/01/17 Javascript
js设置默认时间跨度过程详解
2019/07/17 Javascript
Vue实现星级评价效果实例详解
2019/12/30 Javascript
python使用range函数计算一组数和的方法
2015/05/07 Python
浅谈python for循环的巧妙运用(迭代、列表生成式)
2017/09/26 Python
Python获取指定文件夹下的文件名的方法
2018/02/06 Python
如何基于Python制作有道翻译小工具
2019/12/16 Python
python图形用户接口实例详解
2019/12/16 Python
使用PyTorch训练一个图像分类器实例
2020/01/08 Python
PyTorch笔记之scatter()函数的使用
2020/02/12 Python
python绘制高斯曲线
2021/02/19 Python
Superdry瑞典官网:英国日本街头风品牌
2017/05/17 全球购物
Nike香港官网:Nike HK
2019/03/23 全球购物
龟牌英国商店:Turtle Wax Brand Store UK
2019/07/02 全球购物
财务会计专业求职信范文
2013/12/31 职场文书
项目考察欢迎辞
2014/01/17 职场文书
宝宝周岁宴答谢词
2014/01/26 职场文书
幼儿园亲子活动方案
2014/01/29 职场文书
社区平安建设方案
2014/05/25 职场文书
领导班子整改方案
2014/10/25 职场文书
评职称个人总结
2015/03/05 职场文书