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 相关文章推荐
给apache2.2加上mod_encoding模块後 php5.2.0 处理url出现bug
Apr 12 PHP
一步一步学习PHP(5) 类和对象
Feb 16 PHP
php xml 入门学习资料
Jan 01 PHP
深入解析Session是否必须依赖Cookie
Aug 02 PHP
如何解决PHP无法实现多线程的问题
Sep 25 PHP
WordPress开发中的get_post_custom()函数使用解析
Jan 04 PHP
PHP中strnatcmp()函数“自然排序算法”进行字符串比较用法分析(对比strcmp函数)
Jan 07 PHP
smarty学习笔记之常见代码段用法总结
Mar 19 PHP
PHP实现文件下载【实例分享】
Apr 28 PHP
laravel框架 laravel-admin上传图片到oss的方法
Oct 13 PHP
PHP的垃圾回收机制代码实例讲解
Feb 27 PHP
php 获取音视频时长,PHP 利用getid3 获取音频文件时长等数据
Apr 01 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
追忆往昔!浅谈收音机的百年发展历史
2021/03/01 无线电
用PHP代码给图片加水印
2015/07/01 PHP
编写PHP程序检查字符串中的中文字符个数的实例分享
2016/03/17 PHP
PHP中header函数的用法及其注意事项详解
2016/06/13 PHP
Laravel网站打开速度优化的方法汇总
2017/07/16 PHP
PHP中实现中文字串截取无乱码的解决方法
2018/05/29 PHP
php实现单笔转账到支付宝功能
2018/10/09 PHP
PHP结合Redis+MySQL实现冷热数据交换应用案例详解
2019/07/09 PHP
基于jquery的仿百度搜索框效果代码
2011/04/11 Javascript
JavaScript获取当前页面上的指定对象示例代码
2014/02/28 Javascript
js实现遮罩层弹出框的方法
2015/01/15 Javascript
Javascript实现Web颜色值转换
2015/02/05 Javascript
举例讲解JavaScript substring()的使用方法
2015/11/09 Javascript
js和jq使用submit方法无法提交表单的快速解决方法
2016/05/17 Javascript
浅谈html转义及防止javascript注入攻击的方法
2016/12/04 Javascript
js正则表达式惰性匹配和贪婪匹配用法分析
2016/12/26 Javascript
axios学习教程全攻略
2017/03/26 Javascript
JS实现异步上传压缩图片
2017/04/22 Javascript
JavaScript实现各种排序的代码详解
2017/08/28 Javascript
实战node静态文件服务器的示例代码
2018/03/08 Javascript
vue-router之实现导航切换过渡动画效果
2019/10/31 Javascript
javascript使用Blob对象实现的下载文件操作示例
2020/04/18 Javascript
使用Python操作Elasticsearch数据索引的教程
2015/04/08 Python
常见的在Python中实现单例模式的三种方法
2015/04/08 Python
使用Python的Treq on Twisted来进行HTTP压力测试
2015/04/16 Python
Python使用matplotlib绘图无法显示中文问题的解决方法
2018/03/14 Python
python 除法保留两位小数点的方法
2018/07/16 Python
python中 * 的用法详解
2019/07/10 Python
python通过robert、sobel、Laplace算子实现图像边缘提取详解
2019/08/21 Python
Python 列表推导式需要注意的地方
2020/10/23 Python
耐克中国官方商城:Nike中国
2018/10/18 全球购物
文化活动实施方案
2014/03/28 职场文书
委托书范本
2014/04/02 职场文书
大学生实习鉴定评语
2014/04/25 职场文书
2014年采购部工作总结
2014/11/20 职场文书
2015年秋季新学期寄语
2015/03/25 职场文书