加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 站长学院 > PHP教程 > 正文

PHP错误抑制符(@)导致引用传参失败Bug的分析

发布时间:2020-12-13 05:52:51 所属栏目:PHP教程 来源:网络整理
导读:看下面的例子: div class="codetitle" a style="CURSOR: pointer" data="35143" class="copybut" id="copybut35143" onclick="doCopy('code35143')" 代码如下: div class="codebody" id="code35143" ?php $array = array(1,2,3); function add ($arr) { $arr

看下面的例子:
<div class="codetitle"><a style="CURSOR: pointer" data="35143" class="copybut" id="copybut35143" onclick="doCopy('code35143')"> 代码如下:<div class="codebody" id="code35143">
<?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网友提供的这个有趣的问题.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读