通过前几章的学习,你应该掌握了基本的循环语句。但是你有没有想过,除了循环体本身规定的条件外,还有什么方法能让这个循环在某一个条件满足时就终止循环呢?或者说,跳过指定次数的循环,而不中断后续的循环?本章将向你介绍这些流程控制语句。

break

PHP4 PHP5 PHP7

break 可以用来结束当前 forforeachwhiledo-while 或者 switch 结构的执行。大家在学习 switch的时候就已经遇到过 break 这个语句了,下面来看一下它的具体特性和用法。

比如,下面这个循环,我想在 $i = 5 的时候结束这个循环,就可以这样写:


for ($i=1; $i <= 10; $i++) {
	if ($i === 5) {
		break;
	}
	echo $i;
}
		

这样的话,这个循环就只能输出 1234 而不是 12345678910 了。 他会终止 整个 循环,也就是说从 5 开始,后面的所有循环将不会被执行。同时,break 语句除了默认的写法外,还可以加参数,用于规定跳出第几层循环,一般用于嵌套循环中,这种操作不是很常见。但还是有一个示例给大家演示一下:


$i = 0;
while (++$i) {
    switch ($i) {
    case 5:
        echo "循环到 5<br />\n";
        break 1;  /* 只退出 switch. */
    case 10:
        echo "循环到 10; 彻底退出循环<br />\n";
        break 2;  /* 退出 switch 和 while 循环 */
    default:
        break;
    }
}
		

以上,break 1; 可以省略 1,直接写 break 即可。同时,从 PHP 5.4 之后就不存在 break 0; 的说法了,这么写会抛出致命错误;而且,这个跳出的数字不能以变量作为参数,像 $num = 2; break $num; 也是不合法的。

continue

PHP4 PHP5 PHP7

continue 用来跳过本次循环中剩余的代码,并保证 下次的循环能够继续 执行。还是那个 1 到 10 的例子,我们把 break; 换为 continue; 会输出什么呢?


for ($i=1; $i <= 10; $i++) {
	if ($i === 5) {
		continue;
	}
	echo $i;
}
		

正确答案是输出 1234678910,唯独少了 5。需要注意的是,continue 只会跳过本次循环中位于它后面的代码,如果我的 continue 语句之前也有代码,那么这部分代码是会被执行的。

同样,continue 也是接受参数的,默认是 1,可以省略。和 break 一样,他可以跳出多重循环到循环结尾,比如这样:


$i = 0;
while ($i++ < 5) {
    while (1) {
    	echo $i;
        while (1) {
        	// 直接跳到最外层循环
            continue 3;
        }
        echo '这行代码永远也不会被执行到';
    }
    echo '这行代码也一样';
}
		

省略 continue 后面的分号会导致混淆。下面就是一个错误的例子:


for ($i = 0; $i < 5; ++$i) {
	if ($i == 2)
      	continue
  	print "$i\n";
}
		

实际上从 PHP 5.4 之后这样的书写方式已经会被判定为致命的语法错误。而在这个版本之前只会输出一个 2 。

goto

≥PHP5.3.0 PHP7

goto 是 PHP 5.3 之后新引进的流程控制语句,可以用来跳转到程序中的另一位置。但是这个位置是有限的,比如不能跳出当前文件和方法,也没有办法跳到另外一个函数中。以下是它的用法:


goto a;
echo 'Wow';

a:
echo 'PHP';
		

你觉得 Wow 会被输出吗?答案是不会的,正确的输出是 PHP。是不是和 HTML 中的锚链接理念差不多呢?

你同样可以在循环中使用 goto 语句,像这样:


for($i = 0, $j = 50; $i < 100; $i++) {
    while($j--) {
        if($j == 17) goto end;
    }
}
echo "i = $i";

end:
echo 'J 跳转到了 17,循环结束!';
		

可以看出,gotobreak 都会终止循环的运行,直接跳出循环体。还需要注意的是,它只能从循环体里往外跳,并不能跳到循环体中

return

语言结构 PHP4 PHP5 PHP7

由于 return 经常用于函数的返回,所以会在函数一章中详细介绍使用方法,如果你对函数还不太了解,可以跳过这一节。

如果在一个函数中调用 return 语句,将立即结束此函数的执行并将它的参数作为函数的值返回。

return 是语言结构而不是函数,因此其参数没有必要用括号将其括起来。通常都不用括号,实际上也应该不用,这样可以降低 PHP 的负担。

如果没有提供参数,则一定不能用括号,此时返回 NULL。如果调用 return 时加上了括号却又没有参数会导致解析错误。

用引用返回值时 永远不要 使用括号,这样行不通。只能通过引用返回变量,而不是语句的结果。如果使用 return ($a); 时其实不是返回一个变量,而是表达式 ($a) 的值(当然,此时该值也正是 $a 的值)。

declare

PHP4 PHP5 PHP7

declare 其实不是很常用,它经常配合 ticks 来进行调试,性能测试,实现简单的多任务,或者做一些后台的I/O操作等等... 那 tick 又是什么呢? tick 代表一个 事件,当解释器每执行一次低级语句就会触发 register_tick_function 这个方法。可以粗略的理解为每执行一句 PHP 代码(例如: $num = 1; )就去执行下已经注册的 tick 函数。


function profile() {
    global $tmp;
    printf("当前 tmp 的值为: %d.<br/>",$tmp);
}

//注册tick方法
register_tick_function("profile");

//设定每执行几条语句执行已注册的方法这里设置了3条/每次
declare(ticks = 3) {
    $tmp = 1; //一条简单语句
    $tmp = 2; //一条简单语句
    $tmp = 3; //一条简单语句
    $tmp = 4; //一条简单语句
    $tmp = 5; //一条简单语句
    $tmp = 6; //一条简单语句
    $tmp = 7; //一条简单语句
    $tmp = 8; //一条简单语句
}
		

以上代码运行会输出:


Now tmp is 3.
Now tmp is 6.
Now tmp is 8.
		

再来看一段 walkor 大神的讲解示例:


declare(ticks=1);

// 开始时间
$time_start = time();

// 检查是否已经超时
function check_timeout(){
    // 开始时间
    global $time_start;
    // 5秒超时
    $timeout = 5;
    if(time()-$time_start > $timeout){
        exit("超时{$timeout}秒\n");
    }
}

// Zend引擎每执行一次低级语句就执行一下check_timeout
register_tick_function('check_timeout');

// 模拟一段耗时的业务逻辑
while(1){
   $num = 1;
}

// 模拟一段耗时的业务逻辑,虽然是死循环,但是执行时间不会超过$timeout=5秒
while(1){
   $num = 1;
}
		

上面这个代码示例将会监控死循环,虽然有死循环,但是通过 declare 事件监控后,控制其执行时间不会超过 5 秒,保护其他代码执行。

请登录

WOWPHP 账号登录 GitHub 账号登录

还没有账号?现在去注册一个~