结构控制 (控制结构)
if,elseif…else 和 switch 语句是用来根据不同的条件决定结构控制。
您可以在代码中使用条件语句,让你决定结构控制。PHP 支持三种结构控制发表声明:
- if…else语句 – 使用这种语句的场景:当条件为 true 时,执行一块代码;当条件为 false 时,执行另一块代码。
- elseif 语句 – 与 if…else 配合使用,在若干条件之一为 true 时执行一个代码块。
- switch 语句 – 如果您希望有选择地执行若干代码块之一,请使用 Switch 语句。使用 Switch 语句可以避免冗长的 if..elseif else 代码块。
If…Else 语句
如果你想要执行一些代码如果条件为 true,另一个代码如果条件为 false,使用 If…Else 语句。
语法
if (_condition_)
code to be executed if condition is true;_
else
code to be executed if condition is false;_
例子
下面的例子 如果当前日期是周五,下面的代码将输出 “Have a nice weekend!”,否则会输出 “Have a nice day!”:
<html>
<body>
<?php
$d=date("D");
if ($d=="Fri")
echo "Have a nice weekend!";
else
echo "Have a nice day!";
?>
</body>
</html>
如果条件为真/假并且超过一行的应该被执行,这些代码行应该包含在花括号内:
<html>
<body>
<?php
$d=date("D");
if ($d=="Fri")
{
echo "Hello!<br />";
echo "Have a nice weekend!";
echo "See you on Monday!";
}
?>
</body>
</html>
ElseIf 语句
如果您希望在某个条件为真时执行一些代码,请使用 ElseIf 语句。
语法
if (_condition_)
code to be executed if condition is true;_
elseif (_condition_)
code to be executed if condition is true;
else
code to be executed if condition is false;_
例子
如果当前日期是周五,下面的例子中代码将输出 “Have a nice weekend !”,如果当前日期是周日,否则会输出 “Have a nice day!”:
<html>
<body>
<?php
$d=date("D");
if ($d=="Fri")
echo "Have a nice weekend!";
elseif ($d=="Sun")
echo "Have a nice Sunday!";
else
echo "Have a nice day!";
?>
</body>
</html>
Switch 语句
如果您希望有选择地执行若干代码块之一,请使用 Switch 语句。
使用 Switch 语句可以避免冗长的 if..elseif..else 代码块。
语法
switch (expression)
{
case label1:
code to be executed if expression = label1;
break;
case label2:
code to be executed if expression = label2;
break;
default:
code to be executed
if expression is different
from both label1 and label2;
}
例子
switch 语句的工作的方式在不同寻常。首先它根据表达式中的值然后寻求匹配标签的结果值。如果找到一个值匹配那么与匹配标签相关联的代码将被执行或者没有和表达式的值相匹配的语句将会执行指定的 default 代码。
<html>
<body>
<?php
$d=date("D");
switch ($d)
{
case "Mon":
echo "Today is Monday";
break;
case "Tue":
echo "Today is Tuesday";
break;
case "Wed":
echo "Today is Wednesday";
break;
case "Thu":
echo "Today is Thursday";
break;
case "Fri":
echo "Today is Friday";
break;
case "Sat":
echo "Today is Saturday";
break;
case "Sun":
echo "Today is Sunday";
break;
default:
echo "Wonder which day is this ?";
}
?>
</body>
</html>
更深阅读:(选修)
控制结构也叫流程控制
所谓控制结构也叫流程控制,在计算机程序设计中,典型的流程控制模式包含以下几种:
- 顺序结构
- 选择结构
- 循环结构
- 跳转结构
下面我们来一一介绍 PHP 语言对应的实现。首先在 php_learning/basic
目录下新增 structure.php
存放这篇教程编写的代码。
顺序结构
顺序结构非常简单,就是自上而下的执行程序:
假设我们有一个成绩查询系统,可以查询指定学号同学某科成绩及对应等级,先通过顺序结构初始化系统数据和信息:
这种逐行逐行执行的模式就是顺序结构了,我们通过常量初始化等级和科目编码,再通过二维数组 $data
存放学生成绩信息,其中第一维键名对应的是学生 ID,第二维存放的是该学生每个科目的成绩信息。
选择结构
选择结构又可以细分为单分支、双分支、多分支选择,首先来看单分支结构。
单分支结构
所谓单分支就是指存在一个条件判断和选择:
还是以成绩查询系统为例,我们要查询学生 ID 为 1 的同学语文成绩对应的等级,可以这样编码:
$studentId = '1';
$score = $data[$studentId][YUWEN];
if ($score >= 80 && $score < 90) {
printf("学生 %d 的语文分数: %0.1f, 对应等级是: %s\n", $studentId, $score, A);
}
注:上述代码中,
%0.1f
表示输出的格式化浮点型数据只保留小数点后一位。
在 PHP 中,通过 if
语句来实现选择结构,这种只有一个 if
条件判断的代码称作单分支结构,上述代码的打印结果是:
如果条件不符合,则 if
条件判断失败,什么也不会执行,比如将上述代码中的 $studentId
值设置为 2
,就是这样的效果。
双分支结构
为了处理 if 条件未命中的情况,我们可以引入一个 else 语句处理其他业务逻辑,这种满足 if 条件执行对应业务逻辑,不满足 if 条件,执行 else 设定业务逻辑的代码模式,称之为双分支结构:
我们按照这种分支结构就可以处理 $studentId = '2'
的情况下正常打印语文成绩等级:
$studentId = '2';
$score = $data[$studentId][YUWEN];
if ($score >= 80 && $score < 90) {
printf("学生 %d 的语文分数: %0.1f, 对应等级: %s\n", $studentId, $score, A);
} else {
printf("学生 %d 的语文分数: %0.1f, 对应等级: %s\n", $studentId, $score, "其他等级");
}
上述代码的打印结果是:
多分支结构
这种处理方式虽然可以获取一些明确的信息了,比如成绩数据,但是等级信息不明朗,只是一个粗略的「其他等级」,要在 if 条件不成立的情况下获取明确的等级信息,就需要引入多个 else if
语句增加更多的其他条件判断,最后以一个 else 语句作为兜底(默认分支),这种代码选择结构模式称之为多分支结构:
我们按照多分支的模式重构成绩查询系统代码:
$studentId = '2';
$score = $data[$studentId][YUWEN];
if ($score >= 90) {
printf("学生 %d 的语文分数: %0.1f, 对应等级: %s\n", $studentId, $score, A);
} else if ($score >= 80 && $score < 90) {
printf("学生 %d 的语文分数: %0.1f, 对应等级: %s\n", $studentId, $score, B);
} else if ($score >= 60 && $score < 80) {
printf("学生 %d 的语文分数: %0.1f, 对应等级: %s\n", $studentId, $score, C);
} else if ($score < 60) {
printf("学生 %d 的语文分数: %0.1f, 对应等级: %s\n", $studentId, $score, D);
} else {
printf("学生 %d 的语文分数: %0.1f, 对应等级: %s\n", $studentId, $score, "其他等级");
}
这样一来,就可以正常处理所有学生所有科目成绩的查询和打印了,比如上述代码的打印结果是:
你可以随意切换学生 ID 和科目信息,然后通过命令行执行代码查看打印结果,从而模拟实现成绩查询与打印功能。
switch 分支语句
通过上面的多分支结构已经可以处理所有的场景了,但是代码可读性和可维护性较差,为此,PHP 专门引入了独立的分支语句 switch
来处理这种多分支选择的情况,下面我们通过 switch
语句来重构上面的代码:
$studentId = '2';
$score = $data[$studentId][YUWEN];
/*if ($score >= 90) {
printf("学生 %d 的语文分数: %0.1f, 对应等级: %s\n", $studentId, $score, A);
} else if ($score >= 80 && $score < 90) {
printf("学生 %d 的语文分数: %0.1f, 对应等级: %s\n", $studentId, $score, B);
} else if ($score >= 60 && $score < 80) {
printf("学生 %d 的语文分数: %0.1f, 对应等级: %s\n", $studentId, $score, C);
} else if ($score < 60) {
printf("学生 %d 的语文分数: %0.1f, 对应等级: %s\n", $studentId, $score, D);
} else {
printf("学生 %d 的语文分数: %0.1f, 对应等级: %s\n", $studentId, $score, "其他等级");
}*/
switch ($score) {
case $score >= 90:
$level = A;
break;
case $score >= 80 && $score < 90:
$level = B;
break;
case $score >= 60 && $score < 80:
$level = C;
break;
case $score < 60:
$level = D;
break;
default:
$level = "其他等级";
break;
}
printf("学生 %d 的语文分数: %0.1f, 对应等级: %s\n", $studentId, $score, $level);
我们可以对比这两种实现来看,switch
语句将之前所有的条件判断转移到 case
条件语句中,并且最后通过 default
来兜底,替代之前 else
所承担的功能:当所有 case
条件判断都没有命中(均为 false
),则执行 default
分支中的代码。另外,所有的 case
分支代码最后不要漏掉 break;
语句,这行代码的意思是跳出分支判断,否则,会一直执行从命中分支开始后续所有分支语句中的代码。
上述代码的打印结果和之前完全一致,只是实现方式不同罢了。
循环结构
最后我们来看循环结构,所谓循环结构指的是当符合循环条件(菱形方框)时,则循环执行循环体中的代码(矩形方框):
循环结构的实现一般有 while、do…while、for 循环三种,最终实现的功能一致,只是三者在循环条件的设置上各自不同罢了。
while
要通过 while 循环打印上述成绩信息,可以这样编写实现代码:
$total = count($data);
$i = 1;
while ($i <= $total) {
echo "第 $i 个学生的成绩信息:\n";
print_r($data[$i]);
$i++;
}
在这段代码中,首先获取数据总量 $total
,然后设置一个迭代变量 $i
,每次打印一个学生信息后将迭代变量 +1,直到迭代变量的值超过数据总量,则循环结束。上述代码打印结果如下:
字符串和整型之间可以自动转化,所以我们可以通过整型键名访问字符串类型的学生 ID。
do…while
还可以通过 do…while 循环编写上述代码:
do {
echo "第 $i 个学生的成绩信息:\n";
print_r($data[$i]);
$i++;
} while($i <= $total);
打印结果和 while 循环一致,由于 do…while 循环条件设置在 do 语句块之后,所以存在不管循环条件是否满足,始终执行一次循环体的情况,因此在日常编码中,并不常见。
for
日常编码中,最常见的当属 for 循环了,这种循环语句足够灵活,可读性也更好,我们先通过 for 循环重构上述循环代码:
for ($i = 1; $i <= $total; $i++) {
echo "第 $i 个学生的成绩信息:\n";
print_r($data[$i]);
}
循环条件和迭代变量的初始化、自增逻辑都放到 for (condition) {...}
的 condition
部分,这样业务代码就专注于编写业务逻辑,非常简洁。
foreach
在 PHP 中,对于数组循环遍历,尤其是关联数组遍历,还提供了另一个更加强大简单的语言结构 —— foreach
,通过 foreach
语句,可以更方便地获取键值信息:
foreach ($data as $key => $val) {
...
}
其中 $data
表示待遍历的数组(或者实现 ArrayAccess
接口的类),$key
表示数组的键,$val
表示对应的键值,无需设置迭代变量、循环终止条件,遍历完成后,会自动退出循环,下面我们通过 foreach
来编写上述循环代码:
foreach ($data as $id => $score) {
echo "第 {$id} 个学生的成绩信息:\n";
print_r($score);
}
其中 $id
表示对应的学生 ID,$score
表示学生 ID 对应的学生成绩信息。
是不是更方便?可读性也相较于 for
循环更好,不过适用场景有限,仅能用于数组遍历和循环,对于其他数据结构,或者非数组循环遍历,还是要使用通用性更好的 for
循环。
break vs. continue
在上述循环语句的所有不同实现中,如果想要在到达循环条件之前强制退出,和 switch 语句一样,可以使用 break
语句:
foreach ($data as $id => $score) {
echo "第 {$id} 个学生的成绩信息:\n";
print_r($score);
if ($id == 2) {
break;
}
}
这样,就只会打印到第 2 个学生的成绩:
然后运行 break
退出整个循环体,继续后续主体代码执行。
与 break
类似的还有一个 continue
语句,它的作用和 break 不同,是退出当前循环迭代,然后继续执行当前循环体的下一个循环迭代:
foreach ($data as $id => $score) {
if ($id == 1) {
continue;
}
echo "第 {$id} 个学生的成绩信息:\n";
print_r($score);
if ($id == 2) {
break;
}
}
执行上述代码,只会打印第 2 个学生的成绩信息:
因为当 id == 1
时,会命中第一个 if 条件判断,继而执行 continue
跳出了当前循环,进入了下一个循环周期,打印完学生 2 的信息后,命中第二个 if 条件判断,执行 break
跳出整个循环。
跳转结构
所谓跳转结构其实就是 goto 语句,日常编码中很少使用,就不深入介绍了,感兴趣的同学可以查看官方文档介绍:https://www.php.net/manual/zh/control-structures.goto.php。