msgbartop
PHP语言, PHP扩展, Zend引擎相关的研究,技术,新闻分享 – 左手代码 右手诗
msgbarbottom

28 May 10 PHP错误抑制符(@)导致引用传参失败的Bug

今天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网友提供的这个有趣的问题.


分享到:



Related Posts:

Tags: , , , , ,

17 Responses to “PHP错误抑制符(@)导致引用传参失败的Bug”

  1. battery 6015i 6016i |

    It’s genuinely very difficult in this busy life to listen news
    on TV, thus I just use web for that purpose,
    and take the most recent news.

  2. 风雪之隅-鸟哥文章汇总 | 互联网菜鸟 |

    [...] 28 May 10 PHP错误抑制符(@)导致引用传参失败的Bug  [...]

  3. 生活禁忌 |

    多多支持.

  4. 滴水石穿 » 一些PHP Coding Tips 【转载】 |

    [...] 另外错误抑制符号, 可能会造成一些问题, 参看(PHP错误抑制符(@)导致引用传参失败的Bug); [...]

  5. lwt |

    @add($array);

  6. 【转】一些php code tips « pitaya's blog |

    [...] 另外错误抑制符号, 可能会造成一些问题, 参看(PHP错误抑制符(@)导致引用传参失败的Bug); [...]

  7. PHP Coding Tips | 蜂蜜小熊的家 |

    [...] 另外错误抑制符号, 可能会造成一些问题, 参看(PHP错误抑制符(@)导致引用传参失败的Bug); [...]

  8. PHP Coding Tips | SEO 4 IT - Website Creater |

    [...] 另外错误抑制符号, 可能会造成一些问题, 参看(PHP错误抑制符(@)导致引用传参失败的Bug); [...]

  9. 一些PHP Coding Tips[2011/03/30最后更新] | 风雪之隅 |

    [...] func(); error_reporting($report); 另外错误抑制符号, 可能会造成一些问题, 参看(PHP错误抑制符(@)导致引用传参失败的Bug);最后,错误抑制符在发生错误调试的时候也可能会带来麻烦. 12. [...]

  10. PHP错误抑制符(@)导致引用传参失败的Bug | 万维网黑客联盟 |

    [...] 本文地址: http://www.laruence.com/2010/05/28/1565.html [...]

  11. 过客 |

    大哥,我们之前没有C的开发经验,但也想了解一下PHP的源码。能否把这个例子整个gdb的追踪步骤都写出来呀?谢谢

  12. mahone |

    @雪候鸟
    这样的啊,那isset这样判断下不好么?
    如果不判断穿进去,那是去函数里面判断了是吧 ?

  13. 雪候鸟 |

    @mahone 有的时候, 我们引用一个数组的元素的时候, 这个数组元素可能不存在, 我们为了避免它notice, 就会采用 func(@$array['key']);

  14. mahone |

    错误抑制符是这样用的?add(@$array);
    不是用在函数前面的么?@add($array);
    望求教

  15. 互联生活网 |

    长知识了,

  16. 小熊 |

    长知识了,劳伦斯大叔威武

  17. 網站製作學習誌 » [Web] 連結分享 |

    [...] PHP錯誤抑制符(@)導致引用傳參失敗的Bug [...]

Leave a Reply

*