On this page

PHP if / else / switch / mach 流程控制

流程控制

  • if
  • else
  • elseif/else if
  • 流程控制的替代语法
  • while
  • do-while
  • for
  • foreach
  • break
  • continue
  • switch
  • match
  • declare
  • return
  • require
  • include
  • require_once
  • include_once
  • goto

if

(PHP 4, PHP 5, PHP 7, PHP 8)

if 结构是很多语言包括 PHP 在内最重要的特性之一,它允许按照条件执行代码片段。PHP 的 if 结构和 C 语言相似:

<?php
if (expr)
  statement
?>

<?php
if ($a > $b)
  echo "a is bigger than b";
?>

else

(PHP 4, PHP 5, PHP 7, PHP 8)

经常需要在满足某个条件时执行一条语句,而在不满足该条件时执行其它语句,这正是 else 的功能。else 延伸了 if 语句,可以在 if 语句中的表达式的值为 false 时执行语句。例如以下代码在 $a 大于 $b 时显示 a is bigger than b,反之则显示 a is NOT bigger than b:


<?php
if ($a > $b) {
  echo "a is greater than b";
} else {
  echo "a is NOT greater than b";
}
?>

else 语句仅在 if 以及 elseif(如果有的话)语句中的表达式的值为false 时执行

elseif/else if

(PHP 4, PHP 5, PHP 7, PHP 8)

elseif,和此名称暗示的一样,是 ifelse 的组合。和 else 一样,它延伸了 if语句,可以在原来的 if 表达式值为 false 时执行不同语句。但是和 else 不一样的是,它仅在 elseif 的条件表达式值为 true 时执行语句。例如以下代码将根据条件分别显示 a is bigger than b,a equal to b 或者 a is smaller than b:


<?php
if ($a > $b) {
    echo "a is bigger than b";
} elseif ($a == $b) {
    echo "a is equal to b";
} else {
    echo "a is smaller than b";
}
?>

在同一个 if 语句中可以有多个 elseif 部分,其中第一个表达式值为 true(如果有的话)的 elseif 部分将会执行。在 PHP 中,也可以写成“else if”(两个单词),它和“elseif”(一个单词)的行为完全一样。句法分析的含义有少许区别(如果你熟悉C 语言的话,与之行为相同),但是底线是两者会产生完全一样的行为。

elseif 的语句仅在之前的 if 和所有之前 elseif 的表达式值为 false,并且当前的 elseif 表达式值为 true 时执行。

注意: 必须要注意的是 elseifelse if 只有在类似上例中使用花括号的情况下才认为是完全相同。如果用冒号来定义 if/elseif 条件,那就不能用两个单词的 else if,否则 PHP 会产生解析错误。

流程控制的替代语法

(PHP 4, PHP 5, PHP 7, PHP 8)

PHP 提供了一些流程控制的替代语法,包括 ifwhileforforeachswitch。替代语法的基本形式是把左花括号({)换成冒号(:),把右花括号(})分别换成 endif;endwhile;endfor;endforeach; 以及 endswitch;


<?php if ($a == 5): ?>
A is equal to 5
<?php endif; ?>

在上面的例子中,HTML 内容“A is equal to 5”用替代语法嵌套在 if 语句中。该 HTML 的内容仅在 $a 等于 5 时显示。

替代语法同样可以用在 elseelseif 中。下面是一个包括 elseifelseif 结构用替代语法格式写的例子:


<?php
if ($a == 5):
    echo "a equals 5";
    echo "...";
elseif ($a == 6):
    echo "a equals 6";
    echo "!!!";
else:
    echo "a is neither 5 nor 6";
endif;
?>

注意: 不支持在同一个控制块内混合使用两种语法。

警告 switch 和第一个 case 之间的任何输出(含空格)将导致语法错误。例如,这样是无效的:


<?php switch ($foo): ?>
    <?php case 1: ?>
    ...
<?php endswitch ?>

而这样是有效的,因为 switch 之后的换行符被认为是结束标记 ?> 的一部分,所以在 switchcase 之间不能有任何输出:


<?php switch ($foo): ?>
<?php case 1: ?>
    ...
<?php endswitch ?>

switch

(PHP 4, PHP 5, PHP 7, PHP 8)

switch 语句类似于具有同一个表达式的一系列 if 语句。很多场合下需要把同一个变量(或表达式)与很多不同的值比较,并根据它等于哪个值来执行不同的代码。这正是 switch 语句的用途。

注意:

注意和其它语言不同,continue 语句作用到 switch 上的作用类似于 break。如果在循环中有一个 switch 并希望 continue 到外层循环中的下一轮循环,用 continue 2

>注意:

注意 switch/case 作的是松散比较

下面的例子使用不同方法实现同样的事。一个用一系列的 ifelseif 语句,另一个用 switch 语句。例子不同,但输出相同:

示例 #1 switch 结构


// 这是 switch 语句

switch ($i) {
    case 0:
        echo "i equals 0";
        break;
    case 1:
        echo "i equals 1";
        break;
    case 2:
        echo "i equals 2";
        break;
}

// 相当于:

if ($i == 0) {
    echo "i equals 0";
} elseif ($i == 1) {
    echo "i equals 1";
} elseif ($i == 2) {
    echo "i equals 2";
?>

为避免错误,理解 switch 是怎样执行的非常重要。switch 语句一行接一行地执行(实际上是语句接语句)。开始时没有代码被执行。仅当一个 case 语句中的值和 switch 表达式的值匹配时 PHP 才开始执行语句,直到 switch 的程序段结束或者遇到第一个 break 语句为止。如果不在 case 的语句段最后写上 break 的话,PHP 将继续执行下一个 case 中的语句段。例如:


<?php
switch ($i) {
    case 0:
        echo "i equals 0";
    case 1:
        echo "i equals 1";
    case 2:
        echo "i equals 2";
}
?>

这里如果 $i 等于 0,PHP 将执行所有的 echo 语句!如果 $i 等于 1,PHP 将执行后面两条 echo 语句。只有当 $i 等于 2 时,才会得到“预期”的结果——只显示“i equals 2”。所以,别忘了 break 语句就很重要(即使在某些情况下故意想避免提供它们时)。

switch 语句中条件只求值一次并用来和每个 case 语句比较。在 elseif 语句中条件会再次求值。如果条件比一个简单的比较要复杂得多或者在一个很多次的循环中,那么用 switch 语句可能会快一些。

在一个 case 中的语句也可以为空,这样只不过将控制转移到了下一个 case 中的语句。


<?php
switch ($i) {
    case 0:
    case 1:
    case 2:
        echo "i is less than 3 but not negative";
        break;
    case 3:
        echo "i is 3";
}
?>

一个 case 的特例是 default。它匹配了任何和其它 case 都不匹配的情况。例如:


<?php
switch ($i) {
    case 0:
        echo "i equals 0";
        break;
    case 1:
        echo "i equals 1";
        break;
    case 2:
        echo "i equals 2";
        break;
    default:
        echo "i is not equal to 0, 1 or 2";
}
?>

>注意:

如果有多个 default 将导致
**`E_COMPILE_ERROR`** 错误。

>注意:

从技术上讲,`default` case
可以按照任何顺序列出。只有在没有匹配到其它的 case
时才会使用它。但是最好按照惯例,将其作为最后一个分支放在最后。

如果没有匹配到 case 分支且没有 default 分支,则不会执行任何代码,就像 if 不为 true 一样。

case 的值可以使用表达式。然而,该表达式将会自我求值,然后与 switch 的值进行松散比较。这意味着它不适合用于复杂的 switch 值求值。例如:


<?php
$target = 1;
$start = 3;

switch ($target) {
    case $start - 1:
        print "A";
        break;
    case $start - 2:
        print "B";
        break;
    case $start - 3:
        print "C";
        break;
    case $start - 4:
        print "D";
        break;
}

// 输出“B”
?>

对于更复杂的比较,值 true 可用于 switch 的值。或使用 if-else 代替 switch


<?php
$offset = 1;
$start = 3;

switch (true) {
    case $start - $offset === 1:
        print "A";
        break;
    case $start - $offset === 2:
        print "B";
        break;
    case $start - $offset === 3:
        print "C";
        break;
    case $start - $offset === 4:
        print "D";
        break;
}

// 输出“B”
?>

switch 支持替代语法的流程控制。更多信息见流程控制的替代语法一节。


<?php
switch ($i):
    case 0:
        echo "i equals 0";
        break;
    case 1:
        echo "i equals 1";
        break;
    case 2:
        echo "i equals 2";
        break;
    default:
        echo "i is not equal to 0, 1 or 2";
endswitch;
?>

允许使用分号代替 case 语句后的冒号,例如:


<?php
switch($beer)
{
    case 'tuborg';
    case 'carlsberg';
    case 'stella';
    case 'heineken';
        echo 'Good choice';
        break;
    default;
        echo 'Please make a new selection...';
        break;
}
?>

match

(PHP 8)

match 表达式基于值的一致性进行分支计算。 match表达式和 switch 语句类似, 都有一个表达式主体,可以和多个可选项进行比较。 与 switch 不同点是,它会像三元表达式一样求值。 与 switch 另一个不同点,它的比较是严格比较( ===)而不是松散比较(==)。 Match 表达式从 PHP 8.0.0 起可用。

示例 #1 match 表达式结构


<?php
$return_value = match (subject_expression) {
    single_conditional_expression => return_expression,
    conditional_expression1, conditional_expression2 => return_expression,
};
?>

示例 #2 match 的基础用法


<?php
$food = 'cake';

$return_value = match ($food) {
    'apple' => 'This food is an apple',
    'bar' => 'This food is a bar',
    'cake' => 'This food is a cake',
};

var_dump($return_value);
?>

以上示例会输出:

string(19) "This food is a cake"

>注意:

不一定要使用 `match` 表达式的结果。

>注意:

match 表达式必须使用分号 ; 结尾。

match 表达式跟 switch 语句相似,但是有以下关键区别:

  • match 比较分支值,使用了严格比较 (===),
     而 switch 语句使用了松散比较。
    
  • match 表达式会返回一个值。
  • match 的分支不会像 switch 语句一样,落空时执行下个 case。
  • match 表达式必须彻底列举所有情况。

match 表达式和 switch 语句类似, 逐个检测匹配分支。一开始不会执行代码。 只有在所有之前的条件不匹配主体表达式时,才会执行剩下的条件表达式。 只会执行返回的表达式所对应的匹配条件表达式。 举例:


<?php
$result = match ($x) {
    foo() => ...,
    $this->bar() => ..., // 如果 foo() === $x,不会执行 $this->bar()
    $this->baz => beep(), // 只有 $x === $this->baz 时才会执行 beep() 
    // 等等
};
?>

match 表达式分支可以通过逗号分隔,包含多个表达式。 这是一个逻辑 OR,当多个分支表达式右侧相同时,就可以用这种缩写。


<?php
$result = match ($x) {
    // 匹配分支:
    $a, $b, $c => 5,
    // 等同于以下三个分支:
    $a => 5,
    $b => 5,
    $c => 5,
};
?>

default 模式是个特殊的条件。 当之前的条件都不匹配时,会匹配到该模式。 For example:


<?php
$expressionResult = match ($condition) {
    1, 2 => foo(),
    3, 4 => bar(),
    default => baz(),
};
?>

注意:

多个 default 模式将会触发 **`E_FATAL_ERROR`** 错误。

match 表达式必须详尽列出所有情况。 如果主体表达式不能被任意分支条件处理, 会抛出 UnhandledMatchError

示例 #3 match 表达式存在未处理的示例


<?php
$condition = 5;

try {
    match ($condition) {
        1, 2 => foo(),
        3, 4 => bar(),
    };
} catch (\UnhandledMatchError $e) {
    var_dump($e);
}
?>

以上示例会输出:

object(UnhandledMatchError)#1 (7) {
  ["message":protected]=>
  string(33) "Unhandled match value of type int"
  ["string":"Error":private]=>
  string(0) ""
  ["code":protected]=>
  int(0)
  ["file":protected]=>
  string(9) "/in/ICgGK"
  ["line":protected]=>
  int(6)
  ["trace":"Error":private]=>
  array(0) {
  }
  ["previous":"Error":private]=>
  NULL
}

使用 match 表达式处理非一致性检查

可以使用 match 表达式将 true 作为主项表达式来处理非一致性条件的情况。

示例 #4 针对整数范围,使用宽泛的表达式匹配分支


<?php

$age = 23;

$result = match (true) {
    $age >= 65 => 'senior',
    $age >= 25 => 'adult',
    $age >= 18 => 'young adult',
    default => 'kid',
};

var_dump($result);
?>

以上示例会输出:

string(11) "young adult"

示例 #5 针对字符串内容,使用宽泛的表达式匹配分支


<?php

$text = 'Bienvenue chez nous';

$result = match (true) {
    str_contains($text, 'Welcome') || str_contains($text, 'Hello') => 'en',
    str_contains($text, 'Bienvenue') || str_contains($text, 'Bonjour') => 'fr',
    // ...
};

var_dump($result);
?>

以上示例会输出:

string(2) "fr"