控制结构
到目前为止,我们的文件都是逐行执行的。因此,我们在某些情况下会收到通知,例如当数组不包含我们正在寻找的内容时。如果我们能选择执行哪一行,岂不更好?控制结构来帮忙!
控制结构就像一个交通分流标志。它根据一些预定义的条件来引导执行流。控制结构有很多种,但我们可以将其分为条件式和循环式。条件允许我们选择是否执行一条语句。循环则根据需要多次执行语句。让我们逐一了解一下它们。
条件
条件对布尔表达式(即返回值)进行求值。如果表达式为真,它将执行代码块中的所有内容。代码块是用 {}
括起来的一组语句。让我们看看它是如何工作的:
<?php
echo "Before the conditional.";
if (4 > 3) {
echo "Inside the conditional.";
}
if (3 > 4) {
echo "This will not be printed.";
}
echo "After the conditional.";
在前面的代码中,我们使用了两个条件。条件由关键字 if
和括号中的布尔表达式以及代码块定义。如果表达式为真,则执行代码块,否则跳过代码块。
通过添加关键字 else
,可以增强条件的功能。它告诉 PHP,如果前面的条件没有满足,就执行某个代码块。我们来看一个例子:
if (2 > 3) {
echo "Inside the conditional.";
} else {
echo "Inside the else.";
}
由于 if
的条件未满足,上例将执行 else
内的代码。
最后,您还可以在 elseif
关键字后添加另一个条件和代码块,以继续向 PHP 询问更多条件。您可以根据需要在 if
后添加多个 elseif
。如果添加 else
,它必须是条件链中的最后一个。还要记住,一旦 PHP 发现一个条件解析为 true
,它就会停止评估其余的条件。
<?php
if (4 > 5) {
echo "Not printed";
} elseif (4 > 4) {
echo "Not printed";
} elseif (4 == 4) {
echo "Printed.";
} elseif (4 > 2) {
echo "Not evaluated.";
} else {
echo "Not evaluated.";
}
if (4 == 4) {
echo "Printed";
}
在上一个示例中,第一个求值为 true
的条件就是高亮显示的条件。在此之后,PHP 不会再评估任何条件,直到新的 if
开始。
有了这些知识,让我们试着清理一下应用程序,只在需要时执行语句。将此代码复制到你的 index.php
文件中:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Bookstore</title>
</head>
<body>
<p>
<?php
if (isset($_COOKIE[username'])) {
echo "You are " . $_COOKIE['username'];
} else {
echo "You are not authenticated.";
}
?>
</p>
<?php
if (isset($_GET['title']) && isset($_GET['author'])) {
?>
<p>The book you are looking for is</p>
<ul>
<li><b>Title</b>: <?php echo $_GET['title']; ?></li>
<li><b>Author</b>: <?php echo $_GET['author']; ?></li>
</ul>
<?php
} else {
?>
<p>You are not looking for a book?</p>
<?php
}
?>
</body>
</html>
在这段新代码中,我们以两种不同的方式混合了条件和 HTML 代码。第一种打开了一个 PHP 标记,并添加了一个 if…else
子句,该子句将用 echo
来打印我们是否通过了验证。在条件句中没有合并 HTML 代码,这样就一目了然了。
第二个选项—第二个突出显示的区块—显示了一个更丑的解决方案,但有时也是必要的。当需要打印大量 HTML 代码时,echo
就不那么方便了,最好是关闭 PHP 标记,打印所有需要的 HTML 代码,然后再打开标记。您甚至可以在 if
子句的代码块中这样做,正如您在代码中看到的那样。
混合使用 PHP 和 HTML
如果您觉得我们编辑的最后一个文件看起来相当难看,那就对了。混合使用 PHP 和 HTML 会造成混乱,应该避免。在第 6 章 "适应 MVC" 中,我们将了解如何正确操作。 |
让我们也编辑一下我们的 authenticate.php
文件,因为它正在尝试访问可能不存在的 $_POST
条目。文件的新内容如下:
<?php
$submitted = isset($_POST['username']) && isset($_POST['password']);
if ($submitted) {
setcookie('username', $_POST['username']);
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Bookstore</title>
</head>
<body>
<?php if ($submitted): ?>
<p>Your login info is</p>
<ul>
<li><b>username</b>: <?php echo $_POST['username']; ?></li>
<li><b>password</b>: <?php echo $_POST['password']; ?></li>
</ul>
<?php else: ?>
<p>You did not submit anything.</p>
<?php endif; ?>
</body>
</html>
这段代码还包含我们已经知道的条件。我们正在设置一个变量,以了解我们是否提交了登录信息,并在提交后设置 cookie
。但高亮显示的几行向您展示了在 HTML 中包含条件的新方法。这种方法避免了使用 {}
,而是使用 :
和 endif
,从而使代码在处理 HTML 代码时更具可读性。这两种语法都是正确的,在每种情况下,您都应该使用您认为更易读的语法。
Switch…case
与 if…else
类似的另一种控制结构是 switch…case
。这种结构只评估一个表达式,并根据其值执行代码块。让我们来看一个例子:
<?php
switch ($title) {
case 'Harry Potter':
echo "Nice story, a bit too long.";
break;
case 'Lord of the Rings':
echo "A classic!";
break;
default:
echo "Dunno that one.";
break;
}
switch
子句接收一个表达式(这里是一个变量),然后定义一系列情况。当 case 与表达式的当前值匹配时,PHP 将执行其中的代码。一旦 PHP 发现 break
语句,就会退出 switch…case
。如果没有一个情况适合表达式,PHP 将执行默认情况(如果有的话),但这是可选的。
您还需要知道,如果要退出 switch…case
,break 是必须的。如果不指定中断,即使遇到新的情况,PHP 也会继续执行语句。让我们看一个类似的例子,但没有断点:
<?php
$title = 'Twilight';
switch ($title) {
case 'Harry Potter':
echo "Nice story, a bit too long.";
case 'Twilight':
echo 'Uh...';
case 'Lord of the Rings':
echo "A classic!";
default:
echo "Dunno that one.";
}
如果您在浏览器中测试这段代码,就会发现它打印的是 Uh…A classic! Dunno
that one.
。PHP 发现第二种情况有效,因此执行了它的内容。但由于没有中断,它一直执行到最后。有时这可能是我们想要的行为,但通常不是,所以使用时要小心!
循环
循环是一种控制结构,可让您根据需要多次执行某些语句。您可能会在几种不同的情况下使用循环,但最常见的是在与数组交互时。例如,假设你有一个包含元素的数组,但你不知道里面有什么。您想打印其中的所有元素,因此要对所有元素进行循环。
循环有四种类型。每种循环都有自己的用例,但总的来说,你可以将一种类型的循环转换成另一种类型的循环。让我们仔细看看它们。
While
while
循环是最简单的循环。它执行一个代码块,直到要评估的表达式返回 false
。让我们来看一个例子:
<?php
$i = 1;
while ($i < 4) {
echo $i . " ";
$i++;
}
在上例中,我们定义了一个值为 1
的变量。这个 while
循环执行代码块的内容,直到该表达式为假。正如你所看到的,在循环内部,我们每次都会将 $i
的值递增 1
,因此循环在迭代 4
次后结束。检查脚本的输出,你会看到 "0 1 2 3"。最后打印出来的值是 3,所以当时 $i
的值是 3
。之后,我们将其值增加到 4,所以当 while
子句评估 $i < 4
时,结果是 false
。
Whiles 和无限循环
|
Do…while
do…while
循环与 while
非常相似,都是每次评估一个表达式,并执行代码块,直到该表达式为假。唯一不同的是,当对表达式进行求值时,while
子句会在执行代码前对表达式进行求值,因此有时,如果表达式第一次求值为 false
,我们甚至可能不会进入循环。另一方面,do…while
会在执行代码块后对表达式进行评估,因此即使表达式从一开始就是 false
,循环也至少会执行一次。
<?php
echo "with while: ";
$i = 1;
while ($i < 0) {
echo $i . " ";
$i++;
}
echo "with do-while: ";
$i = 1;
do {
echo $i . " ";
$i++;
} while ($i < 0);
前面的代码用相同的表达式和代码块定义了两个循环,但如果执行它们,你会发现只有 do…while
中的代码被执行。在这两种情况下,表达式从一开始就是 false
,因此 while
甚至没有进入循环,而 do…while
只进入循环一次。
For
for 循环是四个循环中最复杂的一个。它定义了初始化表达式、退出条件和迭代结束表达式。当 PHP 首次遇到循环时,它会执行定义为初始化表达式的内容。然后,对退出条件进行评估,如果评估结果为 true
,则进入循环。执行完循环内的所有内容后,执行迭代结束表达式。完成后,它会再次评估结束条件,循环代码和迭代表达式的结束,直到评估结果为假。和往常一样,一个示例就能说明问题:
<?php
for ($i = 1; $i < 10; $i++) {
echo $i . " ";
}
初始化表达式为 $i = 1
,仅在第一次执行。退出条件为 $i < 10
,在每次迭代开始时执行。迭代结束表达式为 $i++
,在每次迭代结束时执行。这个示例打印了从 1 到 9 的数字。for 循环的另一种更常见的用法是使用数组:
<?php
$names = ['Harry', 'Ron', 'Hermione'];
for ($i = 0; $i < count($names); $i++) {
echo $names[$i] . " ";
}
在本例中,我们有一个名称数组。由于该数组定义为列表,因此其键分别为 0、1 和 2。在第一次迭代中,$i
为 0,在第二次迭代中,$i
为 1,在第三次迭代中,$i
等于 2。当 $i
为 3 时,它不会进入循环,因为退出条件的值为 false
。
每次迭代时,我们都会打印数组中 $i
位置的内容,因此这段代码的结果将是数组中的所有三个名称。
小心退出条件
设置的退出条件不完全符合我们的需要是很常见的,尤其是在数组中。请记住,如果数组是一个列表,则以 0 开始,因此一个包含三个元素的数组将有 0、1 和 2 条目。将退出条件定义为 |
Foreach
最后一种循环是 foreach
循环。这种循环是数组专用的,它允许你完全遍历一个数组,即使你不知道它的键值。语法有两种选择,请参见下面的示例:
<?php
$names = ['Harry', 'Ron', 'Hermione'];
foreach ($names as $name) {
echo $name . " ";
}
foreach ($names as $key => $name) {
echo $key . " -> " . $name . " ";
}
foreach
循环接受一个数组(本例中为 $names
),并指定一个变量,该变量将包含数组条目的值。可以看出,我们不需要指定任何结束条件,因为 PHP 会知道数组何时被迭代完。还可以指定一个变量,其中包含每次迭代的键值,如第二个循环。
对于键值不一定是数字的映射,foreach
循环也很有用。PHP 迭代数组的顺序与在数组中插入内容的顺序相同。
让我们在应用程序中使用一些循环。我们想在主页上显示可用的书籍。我们将书籍列表放入一个数组中,因此必须用一个 foreach
循环遍历所有书籍,打印每本书的一些信息。将以下代码添加到 index.php
的 body
标签中:
<?php endif;
$books = [
[
'title' => 'To Kill A Mockingbird',
'author' => 'Harper Lee',
'available' => true,
'pages' => 336,
'isbn' => 9780061120084
],
[
'title' => '1984',
'author' => 'George Orwell',
'available' => true,
'pages' => 267,
'isbn' => 9780547249643
],
[
'title' => 'One Hundred Years Of Solitude',
'author' => 'Gabriel Garcia Marquez',
'available' => false,
'pages' => 457,
'isbn' => 9785267006323
],
];
?>
<ul>
<?php foreach ($books as $book): ?>
<li>
<i><?php echo $book['title']; ?></i>
- <?php echo $book['author']; ?>
<?php if (!$book['available']): ?>
<b>Not available</b>
<?php endif; ?>
</li>
<?php endforeach; ?>
</ul>
高亮显示的代码还显示了一个使用 :
符号的 foreach
循环,在与 HTML 混合使用时效果更好。它遍历了所有 $books
数组,并以 HTML 列表的形式打印了每本书的一些信息。还要注意的是,我们在循环中加入了一个条件,这完全没有问题。当然,这个条件将针对数组中的每一个条目执行,因此应尽可能简化循环的代码块。