PHP错误抑制符(@)导致引用传参失败的Bug
浏览:2601次 出处信息
今天cici网友发来一个问题, 说是在函数调用参数前面使用错误抑制符号(@)的时候, 貌似引用传参就失效了. 他想让我帮他解答为什么.
看下面的例子:
<?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_REF
问题初步定位了, 但是造成这种差异的原因又是什么呢?
既然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网友提供的这个有趣的问题.
建议继续学习:
- Linus:为何对象引用计数必须是原子的 (阅读:11589)
- 字符引用和空白字符 (阅读:3781)
- 通过引用计数解决野指针的问题(C&C++) (阅读:3481)
- 变量引用可提供执行速度 (阅读:2974)
- 一个想当然造成的错误(函数引用参数的一个问题) (阅读:2456)
- 引用 转发 链式传播 (阅读:1807)
- PHP5.4新特性-解引用实例化 (阅读:1790)
QQ技术交流群:445447336,欢迎加入!
扫一扫订阅我的微信号:IT技术博客大学习
扫一扫订阅我的微信号:IT技术博客大学习
<< 前一篇:PHP上传进度条深度解析
后一篇:php数组排序 >>
文章信息
- 作者:雪候鸟 来源: 风雪之隅
- 标签: 引用 抑制符
- 发布时间:2010-05-29 10:54:49
建议继续学习
近3天十大热文
-
[85] memory prefetch浅析
-
[56] 基本排序算法的PHP实现
-
[50] 深入浅出cassandra 4 数据一致性问
-
[42] 转载:cassandra读写性能原理分析
-
[40] javascript插入样式
-
[39] MySQL半同步存在的问题
-
[38] Inline Form Labels
-
[37] JS中如何判断字符串类型的数字
-
[36] 字符引用和空白字符
-
[34] 获取Dom元素的X/Y坐标