這個本來是之前在微博上有個同學說他經常用來面試別人,大概是說,對於如下代碼,你覺得會輸出啥:

$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++) {
}

至於這倆中寫法孰好孰壞, 那就是蘿蔔白菜了。

最後,大家如果在實際中遇到類似讓大家覺得迷惑的問題,可以留言,也許以後也可以單獨成文。

相關文章