流程控制:中止语句

一个完整的脚本程序应该由一系列语句构成。一条语句也许是一个赋值语句、一个条件判断、一个循环、一个函数调用、或者是什么也不做的空语句。语句通常使用分号结束,并且多个语句可使用花括号进行分组,当做一行语句。

在之前的章节中我们已经学习了赋值语句,这章我们学习 PHP 的流程控制

流程控制包括条件判断(ifelseelseif/else ifswitch)、循环(whiledo-whileforforeach)和中止循环(breakcontinuereturn)等。

上一节我们学习了循环语句,下面我们来看看中止语句


当一个循环未设置或者循环条件出错时,如果循环体内没有中止语句,那么该循环将一直运行,耗费系统资源直至被关闭或者服务器宕机。例如下面代码,如果放在服务器上运行,一段时间后你可能会看到Fatal error: Maximum execution time of 60 seconds exceeded(执行时间超过最大执行时间)的错误提示:


<?php

for ($i=0; ; $i++) { 
    echo ' ';
}

这些是应该避免发生的!一段可能被循环执行的代码应该设置合理的中止条件来跳出循环

在前两节的示例代码中,我们使用了break语句来中止循环,这是一个中止语句,除此之外还有continuereturn等。下面我们分别对它们进行讲解。

break

break表示结束当前循环的执行,仅用于switchwhiledo-whileforforeach结构。

其中switch不属于循环结构,但因特殊性(如果把if结构看做单选题,那么缺少breakswitch结构就类似于连续多选题),经常需要break来中断流程,故break可用于switch结构。

break的使用示例如下:

<?php

// break

// switch结构
$choose = 3;
switch($choose) {
    case 1:
        echo '选项一';
        // break;
    case 2:
        echo '选项二';
        break;
    case 3:
        echo '选项三';
        // break;
    default:
        echo '默认值';
}
// 输出:选项三默认值

// while结构:输出1~100的整数
$i = 1;
while (true) {
    echo '已循环 ', $i, ' 次', PHP_EOL;
    $i++;

    // 设置循环条件
    if($i > 100)
        break;
}

// do-while结构:输出1~100的整数
$i = 1;
do {
    echo '已循环 ', $i, ' 次', PHP_EOL;
    $i++;

    // 设置循环条件
    if($i > 100)
        break;
}while(true);

// for结构:输出1~100的整数
for ($i = 1; ; $i++) { 
    echo '已循环 ', $i, ' 次', PHP_EOL;

    // 设置循环条件
    if($i >= 100)
        break;
}

// foreach结构:查找数组中值为“极速数据”的键值对
$arr = [
    'name'=>'极速数据',
    'host'=>'https://www.jisuapi.com/',
    'column'=>'PHP教程'
];
foreach ($arr as $key => $value) {
    if($value == '极速数据')
        echo $key,': ',$value;
        break;
}
// 输出:name: 极速数据

以上示例只有一重循环(即循环体内无第二个循环体),但若是多重循环(循环体内嵌套循环)呢?请看下面示例:

<?php

// 多重循环嵌套:查找一个二维数组中值为“极速数据”的键值对
$arr = [
    ['一个', '很随便', '的', '数组', '混进了', '听起来', '很高大上的', '二维数组', '我还故意加了一个值','极速数据','来检测多重循环'],
    [1, 2, 3, 4, 5, 6, 7, 8],
    [
        'name'=>'极速数据',
        'host'=>'https://www.jisuapi.com/',
        'columns'=>['PHP教程', 'Python教程', 'HTML5教程', 'Javascript教程'],
        'profile'=>'极速数据平台提供各类生活数据API,方便开发者快速简单的开发APP、软件及其他服务平台。公交、火车、违章、快递等数据应有尽有。',
        'admin'=>'Liu',
        'create'=>2011,
    ]
];
foreach ($arr as $key => $value) {
    foreach ($value as $key2 => $value2) {
        // if(is_array($value2)) {
        //     echo $key2,' : ',json_encode($value2), PHP_EOL;
        // } else {
        //     echo $key2,' : ',$value2, PHP_EOL;
        // }
        if($value2 == '极速数据') {
            echo $key2, ' : ', $value2, PHP_EOL;
            break;
        }
    }
}
/* 输出:
9 : 极速数据
name : 极速数据
*/

以上示例代码中,break只终止了最靠近它的循环。那么如果将需求改为“只检测第一次出现的'极速数据'键值对”呢?那么可以使用break的可选参数来跳出指定的循环层次。示例代码如下:

<?php

// 使用了break接受数字参数决定跳出循环的层数
$arr = [
    ['一个', '很随便', '的', '数组', '混进了', '听起来', '很高大上的', '二维数组', '我还故意加了一个值','极速数据','来检测多重循环'],
    [1, 2, 3, 4, 5, 6, 7, 8],
    [
        'name'=>'极速数据',
        'host'=>'https://www.jisuapi.com/',
        'columns'=>['PHP教程', 'Python教程', 'HTML5教程', 'Javascript教程'],
        'profile'=>'极速数据平台提供各类生活数据API,方便开发者快速简单的开发APP、软件及其他服务平台。公交、火车、违章、快递等数据应有尽有。',
        'admin'=>'Liu',
        'create'=>2011,
    ]
];
foreach ($arr as $key => $value) {
    foreach ($value as $key2 => $value2) {
        if($value2 == '极速数据') {
            echo $key2, ' : ', $value2, PHP_EOL;
            break 2;// 跳出两层循环(从break所在的循环开始)
        }
    }
}
// 输出:9 : 极速数据

上面两段代码去掉注释的话几乎一样,除了在第二段代码中break后跟了一个参数2,它代表break跳出自break所在的循环起的第二层循环

需要注意的是,break只接受整型数字参数或者干脆不接受参数(这代表只跳出一层循环,等同于break 1;),而不接受变量(我们始终坚持使用最新稳定版本的 PHP(大于7.0),而在 PHP 5.4 版本中取消了变量作为break参数传递)。

continue

continuebreak不同,break在英文中是“打断”的意思,而continue则是“继续”。实际上在 PHP 中这二者除了定义不同,使用上别无二致。请看下列示例:

<?php

// continue
$a = 0;
while ($a < 10) {
    $a++;

    if($a == 5)
        continue;
    echo $a , ' ';
}
/* 输出:(其中数字 5 不在其中)
1 2 3 4 6 7 8 9 10
*/

// break
$a = 0;
while ($a < 10) {
    $a++;

    if($a == 5)
        break;
    echo $a , ' ';
}
/* 输出:(从 5 开始不再输出)
1 2 3 4
*/

break跳出整层循环不同,continue仅跳过符合中止条件的后面的代码。例如上面的例子,continue只跳过了当$a == 5条件成立时后面的echo $a , ' ';代码,然后开始下一次的循环。

如果把break比作“断尾求生”,那么continue或许可以比作“蛇类的蜕皮”。同样是舍弃,break要直接的多,continue则属于“断断续续”。请看下方continue在多重循环中的表现:

<?php

// continue 多重循环示例
$arr = [
    ['一个', '很随便', '的', '数组', '混进了', '听起来', '很高大上的', '二维数组', '我还故意加了一个值','极速数据','来检测多重循环', '还在同一数组添加了另一个相同的值', '极速数据', '来验证continue'],
    [1, 2, 3, 4, 5, 6, 7, 8],
    [
        'name'=>'极速数据',
        'host'=>'https://www.jisuapi.com/',
        'columns'=>['PHP教程', 'Python教程', 'HTML5教程', 'Javascript教程'],
        'profile'=>'极速数据平台提供各类生活数据API,方便开发者快速简单的开发APP、软件及其他服务平台。公交、火车、违章、快递等数据应有尽有。',
        'admin'=>'Liu',
        'create'=>2011,
        'test'=>'极速数据'
    ]
];
foreach ($arr as $key => $value) {
    foreach ($value as $key2 => $value2) {
        if($value2 != '极速数据') 
            continue;
        echo $key2, ' : ', $value2, PHP_EOL;
    }
}
/* 输出:
9 : 极速数据
12 : 极速数据
name : 极速数据
test : 极速数据
*/

以上代码输出了二维数组中所有值为“极速数据”的键值对。那么对比一下break

<?php

$arr = [
    ['一个', '很随便', '的', '数组', '混进了', '听起来', '很高大上的', '二维数组', '我还故意加了一个值','极速数据','来检测多重循环', '还在同一数组添加了另一个相同的值', '极速数据', '来验证continue'],
    [1, 2, 3, 4, 5, 6, 7, 8],
    [
        'name'=>'极速数据',// 试试将这行注释掉
        'host'=>'https://www.jisuapi.com/',
        'columns'=>['PHP教程', 'Python教程', 'HTML5教程', 'Javascript教程'],
        'profile'=>'极速数据平台提供各类生活数据API,方便开发者快速简单的开发APP、软件及其他服务平台。公交、火车、违章、快递等数据应有尽有。',
        'admin'=>'Liu',
        'create'=>2011,
        'test'=>'极速数据'
    ]
];
foreach ($arr as $key => $value) {
    foreach ($value as $key2 => $value2) {
        if($value2 != '极速数据') 
            break;
        echo $key2, ' : ', $value2, PHP_EOL;
    }
}
/* 输出:
name : 极速数据
*/

示例代码仅将continue改为break,但结果只输出了二维数组的第三个元素(也是一个数组)的第一个值为“极速数据”的键值对。这里说的有点绕,但是如果二维数组中每个数组的第一个元素值不是“极速数据”的话,这段代码将没有输出!

这也是breakcontinue之间的不同之处。

在使用上,continuebreak类似,同样可以接受一个数字型参数来决定跳出几层循环到循环末尾,默认值也同样是1。请看下面的示例代码:

<?php

// continue 多重循环示例
$arr = [
    ['一个', '很随便', '的', '数组', '混进了', '听起来', '很高大上的', '二维数组', '我还故意加了一个值','极速数据','来检测多重循环', '还在同一数组添加了另一个相同的值', '极速数据', '来验证continue'],
    [1, 2, 3, 4, 5, 6, 7, 8],
    [
        'name'=>'极速数据',
        'host'=>'https://www.jisuapi.com/',
        'columns'=>['PHP教程', 'Python教程', 'HTML5教程', 'Javascript教程'],
        'profile'=>'极速数据平台提供各类生活数据API,方便开发者快速简单的开发APP、软件及其他服务平台。公交、火车、违章、快递等数据应有尽有。',
        'admin'=>'Liu',
        'create'=>2011,
        'test'=>'极速数据'
    ]
];
foreach ($arr as $key => $value) {
    foreach ($value as $key2 => $value2) {
        if($value2 != '极速数据') 
            continue 2;// 跳到第二层循环后开始下一次循环
        echo $key2, ' : ', $value2, PHP_EOL;
    }
}
/* 输出:
name : 极速数据
*/

分析上方代码及结果可知,本段代码仅查找二维数组里每个数组中第一个元素值为“极速数据”的键值对。

在实际开发中,会遇到特别复杂的流程控制,应该根据不同情况选择使用不同的中断语句。即使我们已经知道breakcontinue不同,但有时候修改流程的代码顺序得出结果可能就会一样。在后续的章节中也许会遇到,这里不做过多讲解。

return

return与前面的breakcontinue不同,它的使用非常广泛,常见于函数体。如果用在脚本文件,将会立即结束脚本的运行。例如:

<?php

// return

// 一段运行的代码
echo 'PHP是世界上最好的语言';

// return 一下
return;

// 被 return “阻拦”的代码:不会运行
echo '可怜巴巴';

// 整个脚本将输出:PHP是世界上最好的语言

在函数中,如果调用return语句,将会立刻结束函数的执行。同return名称所暗示的,return是可以接受参数作为返回值的。例如:

<?php

// 一个不带 return 的函数
function demo()
{
    echo '我是一个莫得感情的杀手:我不带返回值', PHP_EOL;
}
$res = demo();// 执行 demo() 函数并将其返回值(不带返回值则返回 NULL)赋给 $res 变量
var_dump($res);// 输出:NULL

function demo2()
{
    echo '我是一个莫得感情的杀手:带的返回值和没带一个样', PHP_EOL;
    return;
}
$res = demo2();// 执行 demo() 函数并将其返回值(不带返回值则返回 NULL)赋给 $res 变量
var_dump($res);// 输出:NULL

// 一个带 return 返回值的函数
function demo3()
{
    echo '我是一个感情丰沛的诗人:我留下了一个返回值',"\n";
    return TRUE;// 可以是任何类型
}
$res = demo3();// 执行 demo() 函数并将其返回值(不带返回值则返回 NULL)赋给 $res 变量
var_dump($res);// 输出:bool(true)

需要注意的是,returnecho一样属于语言结构,而不是函数,其参数不应该使用圆括号括起来。另外,return只能接受一个参数,若要返回多个数据,可以选择将数据存入数组返回:

<?php

function demo()
{
    $val1 = '一个值';
    $val2 = '极速数据';
    $val3 = 666;

    // 返回多个数据:使用数组
    return [$val1,$val2,$val3];
}

$res = demo();
var_dump($res);
/* 输出:
array(3) {
  [0]=>
  string(9) "一个值"
  [1]=>
  string(12) "极速数据"
  [2]=>
  int(666)
}
*/

有关PHP的流程控制我们就讲到这里,截止到本章,PHP 的许多基础概念我们也都学习完毕。下一章我们进入函数的学习!