首頁 >後端開發 >php教程 >PHP錯誤抑制符@導致引用傳參失敗Bug的分析

PHP錯誤抑制符@導致引用傳參失敗Bug的分析

WBOY
WBOY原創
2016-07-29 08:45:031084瀏覽

看下面的範例:

複製程式碼 程式碼如下:


$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:
//...省略
| '不@|do_| (&$1 TSRMLS_CC); }
expr { zend_do_end_silence(&$1 TSRMLS_CC); $$ = $3; }
//此處走了ZEND_SEND_VAL分支
non_empty_function_list_call_function_list } //錯誤的走了這個分支
| variable {..... } //正常情況

所以導致在編譯期間, 生成了不同的OPCODE, 也導致了問題的表象.
最後, 我已經把原因在PHP的這個bug頁做了說明, 有興趣的可以去看看我的爛英語水平. 最後謝謝cici網友提供的這個有趣的問題.
以上就介紹了 PHP錯誤抑制符@導致引用傳參失敗Bug的分析,包括了方面的內容,希望對PHP教程有興趣的朋友有所幫助。

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn