while (condition) { ... } 只要条件为真,就一遍又一遍地运行代码块。每轮开始前都会检查条件,所以如果一开始条件就是假的,循环体一次都不会运行。循环内部必须有东西改变条件,否则它永远不会结束。
这正是 while 擅长的问题:事先不知道要循环几轮,只知道什么时候停。改一下利率,再运行一次看看。
do while:至少运行一次
do { ... } while (condition); 在循环体之后检查条件,所以循环体总会运行一次。注意末尾的分号。
典型的用法是“先尝试,再检查”:掷骰子直到掷出六点,生成验证码直到它没被用过。在有东西可以检查之前,必须先尝试一次。下面这段代码每次运行的结果都不一样:
用 break 退出 while (true)
如果退出条件在循环体中间更容易判断,就写 while (true),再用 break 跳出。和其他循环一样,continue 会直接跳到下一次条件检查。
数组为空时 array_shift() 返回 null,这是另一个出口。这个循环也可以写成 while ($queue),因为空数组会被当作 false。
逐行读取文件
fgets() 每次返回一行,到文件末尾时返回 false,所以可以直接用它驱动 while 循环。下面的代码先写入文件,再把它读回来。
$line = fgets($handle) 外面的括号很重要:先赋值,再把结果和 false 比较。用 !== false 而不是简单的真值判断,可以避免最后一行恰好只有 0(后面没有换行)时循环提前结束。fopen() 页面介绍了文件相关的函数。
在模板中使用 while 和 endwhile
和 if、for 一样,while 也有适合 HTML 的冒号写法:while (...): 和 endwhile;。下面的代码会在“页面”标签页中显示一个倒计时列表。
常见错误:永远不会结束的循环
计数器必须朝着退出条件变化。忘了写 $i++,或者改错了变量,条件就会永远为真。在 Web 服务器上,PHP 会在 max_execution_time(默认 30 秒)之后以致命错误终止脚本;在命令行中,它永远不会停下。
// Never ends: $i is never changed
$i = 0;
while ($i < 3) {
echo $i;
}
对于依赖外部数据的循环,比如重试调用或者分页读取结果,加一个安全上限是成本很低的保护:
多运行几次:有时它很快就成功了,有时它会放弃,但它总会结束。如果事先知道要循环几轮,用 for 循环在一行里写清起点、终点和步长,更不容易出错。
常见问题
PHP 中 while 和 do while 有什么区别?
while 在每轮开始前检查条件,所以循环体可能一次都不运行。do { ... } while ($cond); 在每轮结束后检查,所以循环体至少运行一次。注意 do while 的条件后面有一个分号。
PHP 中怎么停止一个无限 while 循环?
在循环内部,满足退出条件时用 break 结束它:while (true) { ...; if ($done) { break; } }。如果循环没有 break,条件又永远不会变成 false,脚本就会一直运行,直到被 PHP 的 max_execution_time 终止(Web 请求),或者永远运行下去(命令行)。
PHP 中什么时候用 while 而不是 for?
不知道需要循环多少轮时用 while:读取文件直到末尾、重试直到成功、处理队列直到清空。需要计数时用 for,要遍历数组的每个元素时用 foreach。
PHP 有 do until 循环吗?
没有。在 do while 中把停止条件取反即可:do { $n++; } while (!($n >= 3)); 会一直运行,直到 $n >= 3 为真。until 不是 PHP 的关键字。