PHP错误抑制符(@)导致引用传参失败Bug的分析
PHP错误抑制符(@)导致引用传参失败Bug的分析
发布时间:2016-12-29 来源:查字典编辑
摘要:看下面的例子:复制代码代码如下:这个问题,我之前没有遇到过,所以首先去找找相关资料,看看有没有现成的答案,Goolge了一番,发现虽然有人已...

看下面的例子:

复制代码 代码如下:

<?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教程学习
编程开发子分类