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 相关文章推荐
构建简单的Webmail系统
Oct 09 PHP
PHP 组件化编程技巧
Jun 06 PHP
php邮件发送,php发送邮件的类
Mar 24 PHP
PHP中的正则表达式函数介绍
Feb 27 PHP
用来解析.htpasswd文件的PHP类
Sep 05 PHP
深入掌握include_once与require_once的区别
Jun 17 PHP
php字符串截取的简单方法
Jul 04 PHP
PHP return语句的另一个作用
Jul 30 PHP
PHP 信号管理知识整理汇总
Feb 19 PHP
PHP利用正则表达式将相对路径转成绝对路径的方法示例
Feb 28 PHP
php中输出json对象的值(实现方法)
Mar 07 PHP
Laravel 实现在Blade模版中使用全局变量代替路径的例子
Oct 22 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
解析strtr函数的效率问题
2013/06/26 PHP
destoon调用discuz论坛中带图片帖子的实现方法
2014/08/21 PHP
PHP 7的一些引人注目的新特性简单介绍
2015/11/08 PHP
Windows2003下php5.4安装配置教程(IIS)
2016/06/30 PHP
基于yaf框架和uploadify插件,做的一个导入excel文件,查看并保存数据的功能
2017/01/24 PHP
javascript 数组排序函数
2009/08/20 Javascript
js禁止页面使用右键(简单示例代码)
2013/11/13 Javascript
jquery 字符串切割函数substring的用法说明
2014/02/11 Javascript
JS加载器如何动态加载外部js文件
2016/05/26 Javascript
jQuery leonaScroll 1.1 自定义滚动条插件(推荐)
2016/09/17 Javascript
微信小程序 页面跳转如何实现传值
2017/04/05 Javascript
深入理解node.js之path模块
2017/05/03 Javascript
详解React Native顶|底部导航使用小技巧
2017/09/14 Javascript
jQuery实现html双向绑定功能示例
2017/10/09 jQuery
使用vue + less 实现简单换肤功能的示例
2018/02/21 Javascript
vue.js与后台数据交互的实例讲解
2018/08/08 Javascript
JavaScript Array对象使用方法解析
2019/09/24 Javascript
js实现简易拖拽的示例
2020/10/26 Javascript
浅谈es6中的元编程
2020/12/01 Javascript
vue3.0 项目搭建和使用流程
2021/03/04 Vue.js
[10:21]DOTA2-DPC中国联赛 正赛 PSG.LGD vs Aster 选手采访
2021/03/11 DOTA
Python中的异常处理简明介绍
2015/04/13 Python
Python解析最简单的验证码
2016/01/07 Python
Python作用域用法实例详解
2016/03/15 Python
利用Python的turtle库绘制玫瑰教程
2019/11/23 Python
python 抓取知乎指定回答下视频的方法
2020/07/09 Python
详解python中GPU版本的opencv常用方法介绍
2020/07/24 Python
CSS3实现文字波浪线效果示例代码
2016/11/20 HTML / CSS
Joie官方网上商店:购买服装和女装配饰
2018/06/05 全球购物
高二物理教学反思
2014/02/08 职场文书
农业局学习党的群众路线教育实践活动心得体会
2014/03/07 职场文书
大型公益活动策划方案
2014/08/20 职场文书
名人传读书笔记
2015/06/26 职场文书
护理工作心得体会
2016/01/22 职场文书
SpringCloud Feign请求头删除修改的操作代码
2022/03/20 Java/Android
Python的property属性详细讲解
2022/04/11 Python