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 is_file()和is_dir()用于遍历目录时用法注意事项
Mar 02 PHP
php设计模式  Command(命令模式)
Jun 17 PHP
linux下使用ThinkPHP需要注意大小写导致的问题
Aug 02 PHP
php模板原理讲解
Nov 13 PHP
Windows下的PHP安装pear教程
Oct 24 PHP
在Nginx上部署ThinkPHP项目教程
Feb 02 PHP
PHP6新特性分析
Mar 03 PHP
Yii2使用自带的UploadedFile实现的文件上传
Jun 20 PHP
浅析Laravel5中队列的配置及使用
Aug 04 PHP
PHP attributes()函数讲解
Feb 03 PHP
PHP xpath()函数讲解
Feb 11 PHP
Yii2框架加载css和js文件的方法分析
May 25 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对称加密算法示例
2014/05/07 PHP
php5.4以下版本json不支持不转义内容中文的解决方法
2015/01/13 PHP
php中stdClass的用法分析
2015/02/27 PHP
PHP strip_tags保留多个HTML标签的方法
2016/05/22 PHP
php使用curl代理实现抓取数据的方法
2017/02/03 PHP
利用XMLHTTP传递参数在另一页面执行并刷新本页
2006/10/26 Javascript
js玩一玩WSH吧
2007/02/23 Javascript
一起来写段JS drag拖动代码
2010/12/09 Javascript
JavaScript插件化开发教程 (二)
2015/01/27 Javascript
Javascript通过overflow控制列表闭合与展开的方法
2015/05/15 Javascript
简介JavaScript中setUTCSeconds()方法的使用
2015/06/12 Javascript
对JavaScript客户端应用编程的一些建议
2015/06/24 Javascript
基于jQuery实现在线选座之高铁版
2015/08/24 Javascript
JS实现点击登录弹出窗口同时背景色渐变动画效果
2016/03/25 Javascript
全面解析Bootstrap中nav、collapse的使用方法
2016/05/22 Javascript
Bootstrap table简单使用总结
2017/02/15 Javascript
js 获取元素的具体样式信息getcss(实例讲解)
2017/07/05 Javascript
使用javascript做在线算法编程
2018/05/25 Javascript
Mpvue中使用Vant Weapp组件库的方法步骤
2019/05/16 Javascript
详解vue-cli3多页应用改造
2019/06/04 Javascript
Vue使用v-viewer实现图片预览
2020/10/21 Javascript
[07:39]第一届亚洲邀请赛回顾视频
2017/02/14 DOTA
利用Python-iGraph如何绘制贴吧/微博的好友关系图详解
2017/11/02 Python
python判断字符串是否是json格式方法分享
2017/11/07 Python
利用python脚本如何简化jar操作命令
2019/02/24 Python
django settings.py 配置文件及介绍
2019/07/15 Python
使用Python实现 学生学籍管理系统
2019/11/26 Python
Python作用域与名字空间原理详解
2020/03/21 Python
Pandas中两个dataframe的交集和差集的示例代码
2020/12/13 Python
CSS3+font字体文件实现圆形半透明菜单具体步骤(图解)
2013/06/03 HTML / CSS
企划主管岗位职责
2013/12/12 职场文书
食堂个人先进事迹
2014/01/22 职场文书
会计专业毕业自荐书范文
2014/02/08 职场文书
危货运输企业安全生产责任书
2014/07/28 职场文书
教师个人查摆剖析材料
2014/10/14 职场文书
python数字类型和占位符详情
2022/03/13 Python