以前我在面試的時候,遇到許多年輕人都聲稱本身精通php,有過許多項目經驗等等。然而,當真正筆試的時候,我問到php
$result=1; if(-1){ $result=2; } echo $result;
中,$result
最終結果的時候,許多人信誓旦旦的告訴我是1。 試想,這樣一個連基本算法都搞不清楚的人,即便有過再多的項目經驗,你敢用嗎?面試
對於算法的一些問題,我我的一貫是很是較真的,我招人的時候也是很是側重此方面,所以我對php的關注也是在這方面多些。故事得從一個知乎上的問題開始。算法
//第一題 <?php function test(){ $a=1; $b=&$a; echo (++$a)+(++$a); } test(); //執行的值爲6 ?>
//第二題 <?php function test(){ $a=1; $b=&$a; echo (++$a)+(++$a)+(++$a); } test(); //執行的值爲10 ?>
這個問題很是的有意思,也是一個大坑,許多人都算錯了,包括不少我認識的大牛。在這裏就不點名字,以避免其羞愧。 然而你覺得我一開始算對了嗎?我算對了第一題,第二題倒是百思不得其解。最後用調試工具一番調試纔算理清頭緒。索性發出來與你們一塊兒分享這個有意思的問題。php7
這個其實很是簡單,++a
這種單目運算符的運算結果仍是自身。 因此工具
$a=1; $b=&$a; echo (++$a)+(++$a); //換種寫法就等同於 $a=1; $a=++$a; //2 $a=++$a; //3 $a=$a+$a;//3+3=6
哈,不少人確定覺得是等於5,然而這個是操做的同一個變量,等同於改變了兩次$a
的值,最後相加的時候,天然就是改變後的值相加,因此等於6。spa
然而在php中,爲了照顧人類的邏輯,默認狀況下,即便名字相同的基本類型的變量,也不會使用同一個變量地址,所以,以上代碼會被解析爲debug
$a=1; echo (++$a)+(++$a); //換種寫法就等同於 $a=1; $a=++$a; //2 $b=++$a; //3 $a=$a+$b;//2+3=5
可是因爲調試
$b=&$a;
的存在,使得下面的第一個$a
的計算方式變成了傳統的c語言計算方式,因此輸出了_看起來錯誤的結果_。
然而實際上,這個結果反而是正確的。PHP中的糖語法
寵壞了那些基礎原本不紮實的孩子,對這種加法作了特別的運算處理而已。code
爲何說等於6纔是正確結果呢?咱們知道現行高級語言大多來自c語言,php也不例外,咱們這裏用c語言來寫一遍上述代碼,而後經過反彙編
來看看機器究竟是怎麼執行的。 blog
其實不管是否註釋下面的取地址,結果都是6。 咱們看彙編代碼
這裏更清晰的看到a
的值的變化。 便是
mov edx,dword ptr [a] ;a的值爲3 add edx,dword ptr [a] ; 3+3
由問題一的結論來分析問題二,反而陷入了一個更大的舞曲,爲何呢?
echo (++$a)+(++$a)+(++$a); //10 /* 按照問題一的分析,此處的結果應爲 a=1+1 //2 a=a+1 //3 a=a+1 //4 a=a+a+a //12 */
然而輸出的結果倒是10.
這裏咱們用一個工具phpdebug.exe
來調試下看看。
能夠看到的a的值的變化:
1->2->3->4
而後咱們再來調試一下注釋掉
$b=&$a;
的結果。
這裏在第二步的時候從新給了變量$a
一個地址,實際上同是叫$a
,其實他們已經不是同一個變量了。 因此他輸出的結果爲9。
可是爲何上面的結果爲10呢? 這實際上是由於
$b=&$a;
這個取地址運算只起效了一句運算指令,就是隻管事了第一回合,對於之後的運算,php仍是用了日常的算法。 即:
$a=1; $b=&$a; echo (++$a)+(++$a)+(++$a); /* 這段其實是 $a=++$a; //2 $a=++$a; //3 //注意了,前兩個已經獲得結果了,第三個咱們用一個新的變量$c。 $c=++$a; //4 $a=$a+$a; //3+3=6 $a=$a+$c; //6+4=10 */
我認爲出現這種詭異的結果應該算是php的bug,同時,這也說明了此種問題不太容易被發現和暴露,這要求咱們日常寫代碼的時候儘可能使用經常使用的語法,和精幹的語句,讓代碼和邏輯達到最佳的平衡點。 此BUG我已經反饋到php官方。
最新的php7中已經修復了此bug。
初稿 2015-09-11
修訂 2016-05-27
修訂 2016-05-30