PHP Manual
/
基本知识

PHP中的循环和它们的类型

11. 04. 2020

Obsah článku

循环一般用于重复相同的代码部分(通常是在一个数据集上)对于每一种类型的任务,都有不同类型的循环适合,其主要区别在于含义和语法。还需要注意的是,所有类型的循环都是可以相互转换的,只是在代码的复杂性和计算时间上可能并不总是值得的。

循环的基本划分是以元素类型来划分的。

  • for:一个通用的循环,我们事先知道重复的次数,或者可以简单地事先计算出来。
  • whileuntil-while:一个一般的循环,我们事先不知道重复的次数。
  • foreach:浏览数组和对象。
  • 递归":将一个复杂的问题分解成一组较小的问题。

循环的一般属性

循环通常是通过重复一段有标记的代码来实现的,重复只要终止条件成立。循环的停止是由于不能满足终止条件,或者通过调用break;手动停止。

如果没有任何东西停止循环,那么就不能阻止它无限期地运行,或直到应用程序被手动终止,或处理PHP脚本的时间限制用完(通常是30秒)。

重要的术语:

  • 循环"--一种语言表达方式,允许你重复代码的某一部分。
  • 迭代"--循环体的一个具体执行。
  • 初始化"--开始执行一个循环(在第一次迭代开始之前)。
  • 递增"--将一个迭代变量递增1。
  • 退出条件"--在每个迭代中被验证的条件(验证的位置因循环类型而异)。只要条件成立,该循环就会运行

对于循环

For对于我们事先知道重复次数(或可以很容易地计算出来)的情况很有用。例如,它非常适合于区间的线性遍历。

它一般是这样写的(3部分)。

for (inicializace; výraz; inkrementace) {
// 循环的主体
}

  • 初始化:定义循环的初始状态(我们需要哪些变量)。
  • `表达式': 条件。只要它是有效的,该循环就会执行。
  • increment:改变上一次循环的状态(increment-增量为1)。

一个例子是输出一系列从010的数字。

for ($i = 0; $i <= 10; $i++) {
echo $i . '<br>';
}

或者从2100的2的倍数。

for ($i = 2; $i <= 100; $i += 2) {
echo $i . '<br>';
}

for循环对各种技巧很有用,例如获取字母表、数字数组和间隔

当一个do-while循环

只要条件成立,While循环就会运行。while "和 "do-while "的区别在于何时评估条件。

while (výraz) {
// 循环的主体
}

或者说。

do {
// 循环的主体
} while(výraz);

  • while首先评估条件,然后运行内循环。
  • do-while首先处理内循环,然后评估条件。

当我们不能事先知道循环是否会运行,而想保证它总是至少运行一次时,这一点尤其有利(这时我们使用do-while)。

例子。

我们有一个数字存储在变量$x = 2中。我们还想在变量$y中生成一个区间<0; 10>的数字,使其与变量$x中的数字不同。简单地说:在010之间生成一个非2的随机数。

在这种情况下,使用 "do-while "循环很方便。我们事先不知道这个循环要运行多少次(我们可能不走运,一直碰到同一个数字,在这种情况下,这个循环会运行很长时间),而且我们还想保证在条件评估之前至少运行一次,因为我们必须先生成数字。

$x = 2;
$y = $x;
do {
$y = rand(0, 10);
} while($x == $y);
echo 'X :' . $x . '<br>';
echo 'Y:' . $y;

预览器

foreach是浏览字段和对象的完美选择。我们不仅可以得到具体的值,还可以得到键。

如果我们只想获得特定的值。

foreach ($data as $value) {
// 数据处理
}

另外,我们可以拿到钥匙。

foreach ($data as $key => $value) {
// 数据处理
}

foreach是浏览真实数据的完美选择--例如,来自数据库的结果,或者有键的字段。

$countries = [
'en' => '捷克共和国',
'见' => '斯洛伐克',
];
foreach ($countries as $shortcut => $name) {
echo $shortcut . ':' . $name . '<br>';
}

递归

递归发生在一个函数或方法调用自己的时候。它的作用是将一个复杂的问题分解成一组小问题。

对于初学者来说,理解递归可能是一个挑战,因为它是基于责任传递的理念。

该函数实际上说的是 "我不能解决这个问题,但我知道有人可以......",所以它给他打电话,他给别人打电话,......。直到最后一个成员被调用,它就能解决这个问题。

当然值得注意的是,任何递归算法都可以被改写成在不需要递归的地方使用循环(反之亦然)。 递归是一个好的仆人,但却是一个坏的主人。它有助于简单和非常有效地解决某些类型的问题,而通过周期循环则对其他事情很有用。

一般来说,递归是内存密集型的,因为它一直在创建新的函数和方法的实例和语境。然而,对于遍历树形结构来说,例如,这是解决问题的唯一合理方式。

例子。

我们需要计算数字5的阶乘,这就是数学中的计算方法。

5!= 5 * 4 * 3 * 2 * 1

也就是说,从 "1 "到我们感兴趣的 "阶乘 "的一系列数字有一个连续的乘法。

递归地,这可以非常优雅地解决。

function factorial(int $n): int
{
if ($n === 0) {
return 1;
}
return $n * factorial($n - 1);
}

或者,使用三元运算符的更短实现。

function factorial(int $n): int
{
return $n === 0 ? 1 : $n * factorial($n - 1);
}

同样可以改写为使用循环。

function factorial(int $n): int
{
$result = 1;
for ($i = $n; $i > 0; $i--) {
$result *= $i;
}
return $result;
}

用周期写的时间稍长,但同样具有明显的内存占用率。我们只使用一个变量$result进行计算,在这里我们不断地改变数值,不必创建新的factorial()的实例。

非常谨慎地编写无限循环

循环很容易变得无限大(我们通过永不满足终止条件来实现这一点)。你应该考虑到这一点,并可能自己用break;来停止循环。

例如,掷骰子直到掷出数字6。该实施方案倾向于使用while循环。

while (true) {
$value = rand(1, 6);
if ($value === 6) {
echo '价值已经下降' . $value;
break;
}
}

通过写while(true)我们确保了无限次的重复,因为true永远是真的。所以我们必须自己用break;结构来停止循环,但是如果`6'这个值永远不会下降,我们也不会停止循环呢?

就我个人而言,我总是计算重复次数,如果超过某个关键限制,我就强行终止该循环。例如,如果我们超过1000次的尝试。在这种情况下,最好使用for而不是while,并计算运行次数。

如果我们超过了运行的数量,通过抛出一个异常来通知开发者是很礼貌的。

for ($i = 0; $i <= 1000; $i++) {
$value = rand(1, 6);
if ($value === 6) {
echo '价值已经下降' . $value;
break;
}
}
if ($i === 1000) {
throw new \Exception('已经超过了最大的投掷次数。');
}

Jan Barášek   Více o autorovi

Autor článku pracuje jako seniorní vývojář a software architekt v Praze. Navrhuje a spravuje velké webové aplikace, které znáte a používáte. Od roku 2009 nabral bohaté zkušenosti, které tímto webem předává dál.

Rád vám pomůžu:

Související články

1.
12.
Status:
All systems normal.
2024