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页面间传递参数实例代码
Jun 05 PHP
兼容性最强的PHP生成缩略图的函数代码(修改版)
Jan 18 PHP
解析PHP中empty is_null和isset的测试
Jun 29 PHP
Zend Studio 实用快捷键一览表(精心整理)
Aug 10 PHP
codeigniter框架批量插入数据
Jan 09 PHP
简单的php缓存类分享     php缓存机制
Jan 22 PHP
PHP中unset,array_splice删除数组中元素的区别
Jul 28 PHP
在Ubuntu 14.04上部署 PHP 环境及 WordPress
Sep 02 PHP
php+mysqli批量查询多张表数据的方法
Jan 29 PHP
PHP数组操作――获取数组最后一个值的方法
Apr 14 PHP
curl和libcurl的区别简介
Jul 01 PHP
php数据库的增删改查 php与javascript之间的交互
Aug 31 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(一)
2012/03/21 PHP
PHP receiveMail实现收邮件功能
2018/04/25 PHP
tp5框架基于ajax实现异步删除图片的方法示例
2020/02/10 PHP
jquery Mobile入门—外部链接切换示例代码
2013/01/08 Javascript
求数组最大最小值方法适用于任何数组
2013/08/16 Javascript
jQuery模拟点击A标记示例参考
2014/04/17 Javascript
JavaScript观察者模式(经典)
2015/12/09 Javascript
js制作网站首页图片轮播特效代码
2016/08/30 Javascript
详解vue-router2.0动态路由获取参数
2017/06/14 Javascript
前端常见跨域解决方案(全)
2017/09/19 Javascript
vue router-link传参以及参数的使用实例
2017/11/10 Javascript
layui layer select 选择被遮挡的解决方法
2019/09/21 Javascript
浅谈vue异步数据影响页面渲染
2019/10/29 Javascript
深入理解 TypeScript Reflect Metadata
2019/12/12 Javascript
[36:54]Mineski vs Winstrike 2018国际邀请赛小组赛BO2 第一场 8.16
2018/08/17 DOTA
Python使用ntplib库同步校准当地时间的方法
2016/07/02 Python
Python如何为图片添加水印
2016/11/25 Python
python 获取网页编码方式实现代码
2017/03/11 Python
快速查询Python文档方法分享
2017/12/27 Python
python实战之实现excel读取、统计、写入的示例讲解
2018/05/02 Python
详解DeBug Python神级工具PySnooper
2019/07/03 Python
Django DRF APIView源码运行流程详解
2020/08/17 Python
光声世纪笔试题目
2012/08/25 面试题
介绍一下grep命令的使用
2012/06/28 面试题
高职教师岗位职责
2013/12/24 职场文书
初一科学教学反思
2014/01/27 职场文书
幼儿园中秋节活动方案
2014/02/06 职场文书
旅游管理专业大学生职业规划书
2014/02/27 职场文书
小学生操行评语大全
2014/04/22 职场文书
项目工作说明书
2014/07/29 职场文书
反对四风问题自我剖析材料
2014/09/29 职场文书
2014年电厂个人工作总结
2014/11/27 职场文书
中学教代会开幕词
2016/03/04 职场文书
2019年警察入党转正申请书最新范文
2019/09/03 职场文书
2019年最新感恩节祝福语(28句)
2019/11/27 职场文书
Python爬虫实战之爬取携程评论
2021/06/02 Python