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 强制性文件下载功能的函数代码(任意文件格式)
May 26 PHP
解析php中call_user_func_array的作用
Jun 07 PHP
深入PHP autoload机制的详解
Jun 09 PHP
php 批量生成html,txt文件的实现代码
Jun 26 PHP
解密ThinkPHP3.1.2版本之模块和操作映射
Jun 19 PHP
php实现的SESSION类
Dec 02 PHP
thinkPHP2.1自定义标签库的导入方法详解
Jul 20 PHP
Yii框架扩展CGridView增加导出CSV功能的方法
May 24 PHP
浅谈Laravel中的一个后期静态绑定
Aug 11 PHP
ajax+php实现无刷新验证手机号的实例
Dec 22 PHP
PHP中将一个字符串部分字符用星号*替代隐藏的实现代码
Sep 08 PHP
解决laravel session失效的问题
Oct 14 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
第九节--绑定
2006/11/16 PHP
php循环创建目录示例分享(php创建多级目录)
2014/03/04 PHP
PHP的MVC模式实现原理分析(一相简单的MVC框架范例)
2014/04/29 PHP
PHP 生成微信红包代码简单
2016/03/25 PHP
Yii框架中jquery表单验证插件用法示例
2016/10/18 PHP
THINKPHP截取中文字符串函数实例代码
2017/03/20 PHP
js loading加载效果实现代码
2009/11/24 Javascript
javascript禁用键盘功能键让右击及其他键无效
2013/10/09 Javascript
jquery delay()介绍及使用指南
2014/09/02 Javascript
jQuery实现调整表格单列顺序完整实例
2016/06/20 Javascript
jq checkbox 的全选并ajax传参的实例
2017/04/01 Javascript
Angular中使用MathJax遇到的一些问题
2017/12/15 Javascript
jQuery插件Validation表单验证详解
2018/05/26 jQuery
微信小程序将字符串生成二维码图片的操作方法
2018/07/17 Javascript
Vue之Mixins(混入)的使用方法
2019/09/24 Javascript
JavaScript实现更换背景图片
2019/10/18 Javascript
微信小程序在text文本实现多种字体样式
2019/11/08 Javascript
[01:18]一目了然!DOTA2DotA快捷操作对比第一弹
2014/07/01 DOTA
python编写暴力破解FTP密码小工具
2014/11/19 Python
python黑魔法之编码转换
2016/01/25 Python
详解Python中使用base64模块来处理base64编码的方法
2016/07/01 Python
python一键升级所有pip package的方法
2017/01/16 Python
对numpy 数组和矩阵的乘法的进一步理解
2018/04/04 Python
ORM Django 终端打印 SQL 语句实现解析
2019/08/09 Python
使用python写的opencv实时监测和解析二维码和条形码
2019/08/14 Python
python类中super() 的使用解析
2019/12/19 Python
python3实现简单飞机大战
2020/11/29 Python
python中操作文件的模块的方法总结
2021/02/04 Python
Python  Asyncio模块实现的生产消费者模型的方法
2021/03/01 Python
中国最大的名表商城:万表网
2016/08/29 全球购物
药剂专业个人求职信范文
2014/04/29 职场文书
经济管理自荐书
2014/06/09 职场文书
演讲开场白和结束语
2015/05/29 职场文书
2016年教师学习教师法心得体会
2016/01/20 职场文书
Python机器学习之KNN近邻算法
2021/05/14 Python
go goroutine 怎样进行错误处理
2021/07/16 Golang