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 会话(session 时间设定)使用入门代码
Jun 05 PHP
PHP 采集程序 常用函数
Dec 18 PHP
基于php使用memcache存储session的详解
Jun 25 PHP
一个经典的PHP验证码类分享
Nov 18 PHP
PHP版本常用的排序算法汇总
Dec 20 PHP
WordPress中设置Post Type自定义文章类型的实例教程
May 10 PHP
基于PHP实现数据分页显示功能
May 26 PHP
Windows2003下php5.4安装配置教程(Apache2.4)
Jun 30 PHP
PHP中让json_encode不自动转义斜杠“/”的方法
Feb 28 PHP
PHP策略模式定义与用法示例
Jul 27 PHP
php实现的pdo公共类定义与用法示例
Jul 19 PHP
php+layui数据表格实现数据分页渲染代码
Oct 26 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 header函数分析详解
2011/08/06 PHP
php中使用preg_match_all匹配文章中的图片
2013/02/06 PHP
对PHP语言认识上需要避免的10大误区
2014/06/12 PHP
基于PHP如何把汉字转化为拼音
2015/12/11 PHP
Laravel框架中队列和工作(Queues、Jobs)操作实例详解
2020/04/06 PHP
经典的解除许多网站无法复制文字的绝招
2006/12/31 Javascript
javascript replace方法与正则表达式
2008/02/19 Javascript
Jquery升级新版本后选择器的语法问题
2010/06/02 Javascript
使用Mootools动态添加Css样式表代码,兼容各浏览器
2011/12/12 Javascript
JS实现图片翻书效果示例代码
2013/09/09 Javascript
jquery购物车实时结算特效实现思路
2013/09/23 Javascript
JS的location.href跳出框架打开新页面的方法
2014/09/04 Javascript
每天一篇javascript学习小结(Function对象)
2015/11/16 Javascript
JS回调函数简单用法示例
2017/02/09 Javascript
zTree树形插件异步加载方法详解
2017/06/14 Javascript
Angular.js中angular-ui-router的简单实践
2017/07/18 Javascript
angularjs 缓存的使用详解
2018/03/19 Javascript
简单介绍Python中的JSON模块
2015/04/08 Python
Python实现的多叉树寻找最短路径算法示例
2018/07/30 Python
了解不常见但是实用的Python技巧
2019/05/23 Python
Python 给定的经纬度标注在地图上的实现方法
2019/07/05 Python
python实现LRU热点缓存及原理
2019/10/29 Python
Django单元测试中Fixtures用法详解
2020/02/25 Python
解决pyecharts运行后产生的html文件用浏览器打开空白
2020/03/11 Python
Python爬虫获取豆瓣电影并写入excel
2020/07/31 Python
详解Python流程控制语句
2020/10/28 Python
CSS3弹性盒模型开发笔记(一)
2016/04/26 HTML / CSS
任意存:BOXFUL
2018/05/21 全球购物
应届毕业生就业自荐信
2013/10/26 职场文书
执行总经理岗位职责
2014/02/03 职场文书
医学院毕业生自荐信范文
2014/03/06 职场文书
环境工程专业自荐信范文
2014/03/18 职场文书
超市中秋节促销方案
2014/03/21 职场文书
赵氏孤儿观后感
2015/06/09 职场文书
使用numpy nonzero 找出非0元素
2021/05/14 Python
基于Python实现流星雨效果的绘制
2022/03/18 Python