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 相关文章推荐
php5中类的学习
Mar 28 PHP
php计算十二星座的函数代码
Aug 21 PHP
smarty基础之拼接字符串的详解
Jun 18 PHP
php的数组与字符串的转换函数整理汇总
Jul 18 PHP
php中Session的生成机制、回收机制和存储机制探究
Aug 19 PHP
windows8.1下Apache+Php+MySQL配置步骤
Oct 30 PHP
PHP中对数组的一些常用的增、删、插操作函数总结
Nov 27 PHP
php 微信开发获取用户信息如何实现
Dec 13 PHP
浅谈PHP的反射机制
Dec 15 PHP
PHP检查网站是否宕机的方法示例
Jul 24 PHP
使用PHP连接数据库_实现用户数据的增删改查的整体操作示例
Sep 01 PHP
PHP基于堆栈实现的高级计算器功能示例
Sep 15 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/08/10 PHP
php生成验证码,缩略图及水印图的类分享
2016/04/07 PHP
php字符串的替换,分割和连接方法
2016/05/23 PHP
阿里云Win2016安装Apache和PHP环境图文教程
2018/03/11 PHP
TP5(thinkPHP框架)实现后台清除缓存功能示例
2019/05/29 PHP
扩展String功能方法
2006/09/22 Javascript
javascript cookies 设置、读取、删除实例代码
2010/04/12 Javascript
在IE和VB中支持png图片透明效果的实现方法(vb源码打包)
2011/04/01 Javascript
实用的JS正则表达式(手机号码/IP正则/邮编正则/电话等)
2013/01/11 Javascript
JQuery boxy插件在IE中边角图片不显示问题的解决
2015/05/20 Javascript
JavaScript实现动态添加,删除行的方法实例详解
2015/07/02 Javascript
JavaScript学习笔记之数组的增、删、改、查
2016/03/23 Javascript
使用jquery/js获取iframe父子级、同级获取元素的方法
2016/08/05 Javascript
微信小程序 图片宽高自适应详解
2017/05/11 Javascript
javascript中new Array()和var arr=[]用法区别
2017/12/01 Javascript
Vue实现调节窗口大小时触发事件动态调节更新组件尺寸的方法
2018/09/15 Javascript
微信小程序地图实现展示线路
2020/07/29 Javascript
Python求两个list的差集、交集与并集的方法
2014/11/01 Python
Python实现测试磁盘性能的方法
2015/03/12 Python
Python简单删除目录下文件以及文件夹的方法
2015/05/27 Python
Python如何实现MySQL实例初始化详解
2017/11/06 Python
一篇文章了解Python中常见的序列化操作
2019/06/20 Python
python实现两个文件夹的同步
2019/08/29 Python
CSS3 media queries + jQuery实现响应式导航
2016/09/30 HTML / CSS
爱他美官方海外旗舰店:Aptamil奶粉
2017/12/22 全球购物
英国鹦鹉店:Parrot Essentials
2018/12/03 全球购物
main 主函数执行完毕后,是否可能会再执行一段代码,给出说明
2012/12/05 面试题
司法局火灾防控方案
2014/06/05 职场文书
运动会广播稿200字(10篇)
2014/10/12 职场文书
公司员工辞职信范文
2015/05/12 职场文书
同事欢送会致辞
2015/07/31 职场文书
环保建议书范文
2015/09/14 职场文书
祝福语集锦:朋友新店开业祝福语
2019/12/10 职场文书
go原生库的中bytes.Buffer用法
2021/04/25 Golang
Apache SeaTunnel实现 非CDC数据抽取
2022/05/20 Servers