查看原文
其他

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

The following article is from 风雪之隅 Author Laruence

(给程序员的那些事加星标

转自:风雪之隅(鸟哥博客)

www.laruence.com/2020/07/09/6015.html

这个本来是之前在微博上有个同学说他经常用来面试别人,大概是说,对于如下代码,你觉得会输出啥:$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_WITH '(' 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++) {}

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

- EOF -


推荐阅读  点击标题可跳转

1、一次出人意料而名留青史的 DNS 投毒攻击

2、Ubuntu 20.04 LTS 已引入 PHP 7.4

3、7 种 PHP 获取文件扩展名的方法


看完本文有收获?请分享给更多人

关注「PHP开发者」加星标,提升PHP技能


点赞和在看就是最大的支持❤️

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存