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

2015-01-24信息快讯网

今天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_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连接MongoDB示例代码
谨慎使用PHP的引用原因分析
很让人受教的 提高php代码质量36计
php控制linux服务器常用功能 关机 重启 开新站点等
三个类概括PHP的五种设计模式
PHP中使用foreach和引用导致程序BUG的问题介绍
PhpMyAdmin出现export.php Missing parameter: what /export_type错误解决方法
php 调试利器debug_print_backtrace()
PHP Parse Error: syntax error, unexpected $end 错误的解决办法
php错误、异常处理机制(补充)
PHP中的错误处理、异常处理机制分析
无法在发生错误时创建会话,请检查 PHP 或网站服务器日志,并正确配置 PHP 安装(win+linux)
在WAMP环境下搭建ZendDebugger php调试工具的方法
PHP中获取变量的变量名的一段代码的bug分析
php性能优化分析工具XDebug 大型网站调试工具
深入理解PHP原理之错误抑制与内嵌HTML分析
一些PHP Coding Tips(php小技巧)[2011/04/02最后更新]
PHP中使用gettext来支持多语言的方法
php中神奇的fastcgi_finish_request
PHP开发不能违背的安全规则 过滤用户输入
PHP 调试工具Debug Tools
php debug 安装技巧
fleaphp rolesNameField bug解决方法
Drupal 添加模块出现莫名其妙的错误的解决方法(往往出现在模块较多时)
使用NetBeans + Xdebug调试PHP程序的方法
php expects parameter 1 to be resource, array given 错误
PHP如何抛出异常处理错误
PHP开发中的错误收集,不定期更新。
使用XDebug调试及单元测试覆盖率分析
php 变量未定义等错误的解决方法
©2014-2024 dbsqp.com