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 相关文章推荐
用文本文件制作留言板提示(下)
Oct 09 PHP
PHP生成静态页
Nov 25 PHP
php 设计模式之 工厂模式
Dec 19 PHP
解析php session_set_save_handler 函数的用法(mysql)
Jun 29 PHP
linux使用crontab实现PHP执行计划定时任务
May 10 PHP
PHP图片处理之使用imagecopyresampled函数实现图片缩放例子
Nov 19 PHP
微信公众平台DEMO(PHP)
May 04 PHP
深入浅析PHP无限极分类的案例教程
May 09 PHP
PHP实现的redis主从数据库状态检测功能示例
Jul 20 PHP
PHP使用Redis长连接的方法详解
Feb 12 PHP
Mac系统下安装PHP Xdebug
Mar 30 PHP
PHP获取类私有属性的3种方法
Sep 10 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电台频率大全 - 1 北京市
2020/03/11 无线电
小偷PHP+Html+缓存
2006/12/20 PHP
PHP验证码类代码( 最新修改,完全定制化! )
2010/12/02 PHP
使用HMAC-SHA1签名方法详解
2013/06/26 PHP
PHP 导出Excel示例分享
2014/08/18 PHP
PHP实现网页内容html标签补全和过滤的方法小结【2种方法】
2017/04/27 PHP
JQuery 技巧和窍门整理(8个)
2010/04/22 Javascript
javascript 模式设计之工厂模式详细说明
2010/05/10 Javascript
jquery 提交值不为空的元素示例代码
2013/05/10 Javascript
Javascript 修改String 对象 增加去除空格功能(示例代码)
2013/11/30 Javascript
node.js中的fs.lchown方法使用说明
2014/12/16 Javascript
JavaScript实现为指定对象添加多个事件处理程序的方法
2015/04/17 Javascript
jQuery mobile类库使用时加载导航历史的方法简介
2015/12/04 Javascript
JQuery EasyUI的使用
2016/02/24 Javascript
基于BootStrap Metronic开发框架经验小结【一】框架总览及菜单模块的处理
2016/05/12 Javascript
JavaScript获取当前url根目录(路径)
2016/06/17 Javascript
jQuery 调用WebService 实例讲解
2016/06/28 Javascript
js实现html table 行,列锁定的简单实例
2016/10/13 Javascript
connection reset by peer问题总结及解决方案
2016/10/21 Javascript
CentOS环境中MySQL修改root密码方法
2018/01/07 Javascript
微信小程序实现聊天对话(文本、图片)功能
2018/07/06 Javascript
详解微信小程序与内嵌网页交互实现支付功能
2018/10/22 Javascript
js纯前端实现腾讯cos文件上传功能的示例代码
2019/05/14 Javascript
javascript设计模式 ? 外观模式原理与用法实例分析
2020/04/15 Javascript
深入学习Python中的上下文管理器与else块
2017/08/27 Python
Python实现OpenCV的安装与使用示例
2018/03/30 Python
Python3中内置类型bytes和str用法及byte和string之间各种编码转换 问题
2018/09/27 Python
pandas 快速处理 date_time 日期格式方法
2018/11/12 Python
Django框架会话技术实例分析【Cookie与Session】
2019/05/24 Python
Python一键安装全部依赖包的方法
2019/08/12 Python
python zip()函数的使用示例
2020/09/23 Python
HTML5视频支持检测(检查浏览器是否支持视频播放)
2013/06/08 HTML / CSS
英国领先的维生素和补充剂品牌:Higher Nature
2019/08/26 全球购物
个人自我评价范文
2014/02/05 职场文书
Python 数据可视化之Matplotlib详解
2021/11/02 Python
MySQL派生表联表查询实战过程
2022/03/20 MySQL