Press "Enter" to skip to content

一个关于if else容易迷惑的问题

这个本来是之前在微博上有个同学说他经常用来面试别人,大概是说,对于如下代码,你觉得会输出啥:

$a = true;
if ($a) {
  echo "true";
} else label: {
  echo "false";
}

当时觉得有点偏,没想写,今天中午又有人问我,我想那就介绍下这个原因吧.

首先,上面的代码输出truefalse, 如果你知道原因,那就不用继续往下看了,如果不知道,那么:

这块让人比较迷惑的原因可能是因为,我们会很直观的认为:

label : {
  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。

但label这块稍微有点特别(可以说是一个设计违反直觉的”缺陷”吧), 在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(语句),但标签(label)有点不同,”label :”本身会规约为一条statement, 这就导致了这个看起来比较迷惑的问题的出现,他本质上就变成了:

$a = true;
if ($a) {
 echo "true";
} else {
 label: ;  //单独的一条语句
}
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++) {
}

至于这俩中写法孰好孰坏, 那就是萝卜白菜了。

最后,大家如果在实际中遇到类似让大家觉得迷惑的问题,可以留言,也许以后也可以单独成文。

33 Comments

  1. haonan
    haonan April 23, 2021

    99.99%的人原理都懂,但有99%的人会跳坑里吧。。。

  2. William
    William April 7, 2021

    我的天老爷 这么写大概会被打的吧

  3. 虢国技酱
    虢国技酱 January 20, 2021

    代码格式化工具 会自动转换这种写法

  4. Tony
    Tony January 11, 2021

    考察这些还不如开发规范中约定ifelse必须带花括号。

  5. owen
    owen December 22, 2020

    我一般都这样写
    if (count($array) == 0) {
    //数组为空的逻辑
    }
    for ($i = 0; $i < count($array); $i++) {
    }

  6. 晓得博客
    晓得博客 December 13, 2020

    细节决定成败 还是鸡蛋里面挑骨头呢

  7. joy
    joy November 27, 2020

    真棒啊

  8. Ricky C.
    Ricky C. November 7, 2020

    这种理解好像太复杂.
    因为您把 else {statement} 看成了一种语法
    实际上只是else后面因为是单条语句而省略了花括号
    就如
    if($a){
    echo ‘a’;
    }else{
    foreach($a as $v){
    echo $v;
    }
    }
    这里的花括号都可以省略, 所以简写成
    if($a)
    echo ‘a’;
    else foreach($a as $v)
    echo $v;
    这并不是一种语法

    • 王召波
      王召波 February 4, 2021

      对于不懂Clang的人来说, 这么理解还真的是简单易懂. O(∩_∩)O哈哈~

  9. Leo
    Leo October 26, 2020

    感觉你在黑微博面试官,但是我拿不出证据

  10. sam
    sam September 27, 2020

    这种人聪明,但是没把聪明用到改用的地方。真是闲的蛋疼,写代码是让人看懂而不是显的自己多高深,没有任何意义。

  11. hrdeswgtr
    hrdeswgtr September 12, 2020

    不喝拉倒,梁惠凯说:“两件事,沙子的事儿冬冬给你说了吧?还有一件事儿,矿山正式投产了,目前是微利,但是马上就能卖石子,这样就能盈利了。按照咱们的约定,给你百分之二十的利润。你给我个卡号,每个月打给你。”http://szntpioewkuy.bravesites.com/

  12. Ganlv
    Ganlv September 9, 2020

    我反倒是觉得,知道答案才不正常,这人是不是从哪看到了漏的题,提前找了答案。

  13. Joffe Chiu
    Joffe Chiu September 8, 2020

    我经常if else for….

  14. www
    www August 18, 2020

    这反人类的写法,当作语法研究研究还可以;如果在项目这样搞,可以滚蛋了!

  15. 字节
    字节 August 17, 2020

    ifelse的奇技淫巧,啧啧啧….

  16. 暗桔子
    暗桔子 August 4, 2020

    看到大佬们的回复,知道了也不敢这么用了 😂

  17. yong
    yong August 3, 2020

    底层有意思

  18. Jenson
    Jenson July 28, 2020

    反人类自觉的代码,居然有人拿来做面试题,有多大意思?

    • denny yang
      denny yang August 6, 2020

      喜欢装13的人才会问这种东西吧 ,之前去某公司,问二进制,我真想问候他呢。净搞些没用的

  19. jaggle
    jaggle July 27, 2020

    如果有人这样在我的项目里写代码,我就让他滚蛋

  20. f
    f July 24, 2020

    f

  21. salmonl
    salmonl July 12, 2020

    一个细节一个细节掌握

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.