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代码
Dec 06 PHP
discuz安全提问算法
Jun 06 PHP
phpmyadmin 访问被拒绝的真实原因
Jun 15 PHP
javascript 小型动画组件与实现代码
Jun 02 PHP
php数组合并array_merge()函数使用注意事项
Jun 19 PHP
thinkphp中html:list标签传递多个参数实例
Oct 30 PHP
使用php的HTTP请求的库Requests实现美女图片墙
Feb 22 PHP
PHP动态规划解决0-1背包问题实例分析
Mar 23 PHP
如何实现php图片等比例缩放
Jul 28 PHP
PHP 极验验证码实例讲解
Sep 29 PHP
PHP基于GD2函数库实现验证码功能示例
Jan 27 PHP
解决在laravel中leftjoin带条件查询没有返回右表为NULL的问题
Oct 15 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
一个高ai的分页函数和一个url函数
2006/10/09 PHP
PHP array操作10个小技巧分享
2011/06/23 PHP
解析PHP中DIRECTORY_SEPARATOR,PATH_SEPARATOR两个常量的作用
2013/06/21 PHP
详解no input file specified 三种解决方法
2019/11/29 PHP
关于PHP中interface的用处详解
2020/07/26 PHP
JavaScript 自动分号插入(JavaScript synat:auto semicolon insertion)
2009/11/04 Javascript
广泛收集的jQuery拖放插件集合
2012/04/09 Javascript
文本域光标操作的jQuery扩展分享
2014/03/10 Javascript
JS对img标签进行优化使用onerror显示默认图像
2014/04/24 Javascript
JavaScript中document对象使用详解
2015/01/06 Javascript
浅析BootStrap模态框的使用(经典)
2016/04/29 Javascript
Bootstrap Table服务器分页与在线编辑应用总结
2016/08/08 Javascript
js替换字符串中所有指定的字符(实现代码)
2016/08/17 Javascript
laydate.js日期时间选择插件
2017/01/04 Javascript
用原生js做单页应用
2017/01/17 Javascript
javascript闭包功能与用法实例分析
2017/04/06 Javascript
jQuery自动或手动图片切换效果
2017/10/11 jQuery
在nuxt中使用路由重定向的实例
2020/11/06 Javascript
python处理PHP数组文本文件实例
2014/09/18 Python
利用python求相邻数的方法示例
2017/08/18 Python
Python自定义函数定义,参数,调用代码解析
2017/12/27 Python
python爬取个性签名的方法
2018/06/17 Python
python中scikit-learn机器代码实例
2018/08/05 Python
python实现多张图片拼接成大图
2019/01/15 Python
Python Flask框架模板操作实例分析
2019/05/03 Python
python设置中文界面实例方法
2020/10/27 Python
HTML5不支持frameset的两种解决方法
2016/11/14 HTML / CSS
英国健身仓库:Bodybuilding Warehouse
2019/03/06 全球购物
Urban Decay官方网站:美国化妆品品牌
2020/06/04 全球购物
大学毕业生通用自我评价
2014/01/05 职场文书
服装电子商务创业计划书
2014/01/30 职场文书
大学毕业感言100字
2014/02/03 职场文书
免职证明样本
2014/10/23 职场文书
物业保洁员岗位职责
2015/02/13 职场文书
2015年大学社团工作总结
2015/04/09 职场文书
DjangoRestFramework 使用 simpleJWT 登陆认证完整记录
2021/06/22 Python