一個關於if else容易迷惑的問題
這個本來是之前在微博上有個同學說他經常用來面試別人,大概是說,對於如下代碼,你覺得會輸出啥:
$a = true; if ($a) { echo “true”; } else lable: { echo “false”; }
當時沒想寫,今天中午又有人問我,我想那就介紹下這個原因吧.
首先,上面的代碼輸出truefalse, 如果你知道原因,那就不用繼續往下看了,如果不知道,那麼:
這塊讓人比較迷惑的原因可能是因爲,我們會很直觀的認爲:
lable : { statement; }
應該是一個整體, 就好比類似:
if ($a) { } else switch($a) { }
或者:
if ($a) { } else do { } while (!$a);
因爲在PHP的語法設計中,if else本質上是:
if_stmt: if_stmt_without_else T_ELSE statement
也就是說,else後面可以接一切statement,如果條件不成立,執行流就跳到else後面的statement,而while, switch都可以歸約爲statement。
但lable這塊稍微有點特別(可以說是一個設計違反直覺的”缺陷”吧), 在zend_language_parser.y中:
statement: ... | T_DO statement T_WHILE '(' expr ')' ';' {...} | T_SWITCH '(' expr ')' switch_case_list {...} | T_STRING ‘:’ { $$ = zend_ast_create(ZEND_AST_LABEL, $1); }
大家可以看到, do while, switch 都會聯合他們的body歸約爲statement(語句),但標籤(lable)有點不同,”lable :”本身會規約爲一條statement, 這就導致了這個看起來比較迷惑的問題的出現,他本質上就變成了:
$a = true; if ($a) { echo "true"; } else { lable: ; //單獨的一條語句 } echo "false";
最後多說一句,我忘了之前在那看到的,說是這個世界上本無elseif,有的只不過是else (if statement),本質上其實就跟這個意思是一樣的。 就是,else後面可以接語句(statement)。
善用這個結合switch, for, do while等,有的時候可以讓我們的代碼更精簡。
比如,我們要遍歷處理一個數組,當數組的長度爲零的時候,要做點其他事,那很多人可能會這麼寫:
if (count($array)) { for ($i = 0; $i < count($array); $i++) { } } else { //數組爲空的邏輯 }
但你也可以寫成:
if (count($array) == 0) { //數組爲空的邏輯 } else for ($i = 0; $i < count($array); $i++) { }
至於這倆中寫法孰好孰壞, 那就是蘿蔔白菜了。
最後,大家如果在實際中遇到類似讓大家覺得迷惑的問題,可以留言,也許以後也可以單獨成文。