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 Socket 编程
Apr 09 PHP
php动态实现表格跨行跨列实现代码
Nov 06 PHP
让codeigniter与swfupload整合的最佳解决方案
Jun 12 PHP
Thinkphp实现自动验证和自动完成
Dec 19 PHP
PHP通过微信跳转的Code参数获取用户的openid(关键代码)
Jul 06 PHP
PHP命令行执行整合pathinfo模拟定时任务实例
Aug 12 PHP
Laravel Intervention/image图片处理扩展包的安装、使用与可能遇到的坑详解
Nov 14 PHP
PHP后期静态绑定实例浅析
Dec 21 PHP
ThinkPHP5.0框架验证码功能实现方法【基于第三方扩展包】
Mar 11 PHP
Laravel框架控制器的request与response用法示例
Sep 30 PHP
在laravel5.2中实现点击用户头像更改头像的方法
Oct 14 PHP
PHP7创建COOKIE和销毁COOKIE的实例方法
Feb 03 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
全国FM电台频率大全 - 10 江苏省
2020/03/11 无线电
php flush类输出缓冲剖析
2008/10/19 PHP
PHP中for与foreach的区别分析
2011/03/09 PHP
PHP解决URL中文GBK乱码问题的两种方法
2014/06/03 PHP
php中操作memcached缓存进行增删改查数据的实现代码
2014/08/15 PHP
php数组和链表的区别总结
2019/09/20 PHP
Javascript中的常见排序算法
2007/03/27 Javascript
Jquery 在页面加载后执行的几种方式
2014/03/14 Javascript
jQuery晃动层特效实现方法
2015/03/09 Javascript
QQ登录背景闪动效果附效果演示源码下载
2015/09/22 Javascript
JavaScript模拟数组合并concat
2016/03/06 Javascript
图文详解Heap Sort堆排序算法及JavaScript的代码实现
2016/05/04 Javascript
JS 清除字符串数组中,重复元素的实现方法
2016/05/24 Javascript
javascript获取select标签选中的值
2016/06/04 Javascript
ztree实现左边动态生成树右边为内容详情功能
2017/11/03 Javascript
nodejs实现超简单生成二维码的方法
2018/03/17 NodeJs
jQuery实现的五星点评功能【案例】
2019/02/18 jQuery
JavaScript的查询机制LHS和RHS解析
2019/08/16 Javascript
JS实现随机抽选获奖者
2019/11/07 Javascript
Python外星人入侵游戏编程完整版
2020/03/30 Python
python 生成器和迭代器的原理解析
2019/10/12 Python
Django自关联实现多级联动查询实例
2020/05/19 Python
Pymysql实现往表中插入数据过程解析
2020/06/02 Python
Bogner美国官网:滑雪服中的”Dior”
2018/01/30 全球购物
函授本科自我鉴定
2013/11/03 职场文书
铁路个人事迹材料
2014/01/30 职场文书
社团活动总结范文
2014/04/26 职场文书
市政管理求职信范文
2014/05/07 职场文书
员工试用期转正自我评价
2015/03/10 职场文书
2016参观监狱警示教育活动心得体会
2016/01/15 职场文书
《穷人》教学反思
2016/02/19 职场文书
2016年小学中秋节活动总结
2016/04/05 职场文书
私人贷款担保书该怎么写呢?
2019/07/02 职场文书
高中班主任工作总结(范文)
2019/08/20 职场文书
深入理解python协程
2021/06/15 Python
SpringBoot整合MongoDB的实现步骤
2021/06/23 MongoDB