第四章 程序控制
本章深入PHP内部,讲述如何使用函数、表达式和语句以实现对程序的控制。
前面的章节初步介绍了怎样操作数据,如果我们将操作数和操作符看作是构筑元件的话,那么它们组合起来即可形成表达式。进一步讲,表达式可以构成语句,语句用于组成函数,而函数则可用来组成程序。
提示:在学习有关编程语言的基本元素时,从全局理解--即理解这些元素是如何组成一个完整程序的--可能非常困难。但也不必着急,乐观一点。接下来的章节将逐步的显示整个程序,并且一点一点的解释它们是如何构造的。
4.1 表达式
当操作数和操作符组合到一起时,它们即组成表达式。本书的例子中已经展示了许多表达式,然而直到现在,我们才开始将注意力集中在它们身上。
表达式是由一个或多个操作符连接起来的操作数,用来计算出一个值--标量或数组。
最基本的表达式就是数字:
12
从这个简陋的开始,将逐步讨论越来越复杂的表达式:
-12
-12 + 14
-12 + 14 * (24 / 12)
(-12 + 14 * (24 / 12))&& calculate_total_cost()
注意每个表达式,在不考虑复杂性的情况下,每一个表达式事实上是由较小的表达式和一个或多个操作数共同组成的。当计算机编程者使用要定义的概念为该概念下定义时,这称为递归。当一个递归完成时,表达式能被分成较更简单的部分,直到计算机能完全的执行每一部分。
4.1.1 简单表达式
简单表达式是由一个单一的赋值符或一个单一函数调用组成的。由于这些表达式很简单,所以也没必要过多讨论。下面是一些例子:
* initialize_pricing_rules() -- 调用函数。
* $str_first_name = 'John' -- 初始化标量。
* $arr_first_names = array( 'John', 'Marie') -- 初始化数组。
4.1.2有副作用的简单表达式
表达式在它的主要任务之外,还有其它的副作用。当一个或几个变量改变了它们的值,并且这些改变并不是赋值操作符的操作结果时,就会出现这种副作用。例如,一个函数调用可以设置全局变量(全局变量是指在函数内部用global关键字来指定的变量),或者加一操作符也可以改变变量的值。副作用会使得程序很难读懂,因此编程的一个目标就是应该尽可能地减少这种副作用。
不使用global关键字是避免副作用的一个好选择。
让我们看看以下有副作用的表达式例子:
* $int_total_glasses = ++$int_number_of_glasses
-- $int_number_glasses变量在加一以后,再把值赋予$int_total_glasses。
* function one() {global $str_direction_name; $str_directory_name = '/dos_data'; }
-- 当one()函数调用后,全局变量的值将被改变。
4.1.3 复杂表达式
复杂表达式可以以任何顺序使用任意数量的数值、变量、操作符和函数。
尽可能使用简短的表达式,这意味着它们更容易维护。
以下是一些例子:
* ((10+2) /count_fishes() * 114)
-- 包含有三个操作符和一个函数调用的复杂表达式。
* initialize_count( 20 -($int_page_number -1) * 2)
-- 有一个复杂表达式参数的简单函数调用。
提示:有时很难分清左括号和右括号的数目是否相同。从左到右,当左括号出现时,就加一,当右括号出现时,就从总数中减一。如果在表达式的结尾时,总数为零时,左圆括号和右圆括号的数目就一定相同了。
4.2 语句
所有的PHP程序都是由语句构成的,无论是简单的语句,还是复杂的语句,这些语句按顺序执行每一时刻执行一句,直到遇到程序结束、跳转语句、分支语句。
最基本的语句是:
;
此语句什么也没有做,但它仍是合法的。分号符是语句结束的标志。如果需要,语句也可以相当复杂。例如:
$str_house_size =(
$int_number_of_rooms > 9 ?
"large" :
"small"
);
这行代码在房子的数目大于9时,给$str_house_size赋予"large",否则给$str_house_size赋予"small"。
就象人类语言中的语句一样,PHP语句可以分为几个组成部分。在PHP中,组成部分可以是数值、变量、函数和关键字。关键字是PHP留作自己用的单词。这些关键字(_FILE_, _LINE_, if, else, elseif, while, do, for, break, continue, switch, case, default, require, include, function),是组成PHP语言必不可少的,使用它们可以控制程序的流程。
本书将不对关键字_FILE_和_LINE_作介绍,相关内容请参考PHP文档。关键字require和include用来读取和执行PHP脚本, 在PHP手册中有详细介绍。以下部分将重点讲述其余的关键字。
4.2.1 语句类型
PHP共有6种类型语句,如表4.1所示。
表4.1 PHP数据类型
语句类型
描述
非执行语句
需要计算但不执行动作。
执行语句
执行某一动作。
赋值语句
给变量赋值。
判断语句
判断条件,并决定执行哪一个动作。
循环语句
重复执行一系列语句直到某条件为真或直到某条件为假为止。
跳转语句
无条件改变程序流程到程序中另一行继续执行。
非执行语句:
所谓非执行语句,就是PHP需要计算,但并不需要执行什么动作的语句。例如:语句10 + 20,其值是30,但由于没有改变哪个变量值,所以也不需要作什么动作。结果值将不保留,当下一条语句出现时,它很快就被丢弃了。
什么动作也不需要做,那么非执行语句又有什么用呢?我不清楚,如果你能发现它们的用途请告诉我。
执行语句:
执行语句是通过表达式来执行某些动作。它们可以增加或减小某一变量值,或者调用一个函数。执行语句是PHP中使用最多的一种语句类型。
赋值语句:
赋值语句并不复杂,它们可以给一个变量赋予一个数值。关于赋值操作符在前一章“PHP中的数据处理”中已经讲过,在此不再过多赘述。
判断语句:
判断语句使用if 和switch关键字,基于一个表达式的计算结果以决定执行某一段语句,或者基于表达式的结果在两段语句行中选择执行其中的一个。例如,如果要处理的支票值大于1000美圆,则执行一段程序;如果支票数小于1000美圆,就执行另一段程序。
if关键字
在if语句中通过计算表达式,得出真或假值,根据所求出的真、假值来决定执行哪一段程序。
最常见的有以下三种类型的if语句:
1.
if ( EXPRESSION ) {
// code block to be executed when
// expression is true.
}
2.
if ( EXPRESSION ) {
// code block to be executed when
// expression is true.
}
else {
// code block to be executed when
// expression is false.
}
3.
if ( EXPRESSION_1 ) {
// code block to be executed when
// expression_1 is true.
}
elseif ( EXPRESSION_2 ) {
// code block to be executed when
// expression_2 is true.
}
else {
// code blcok to be executed when
// all expression are false.
}
表达式可以包含第三章“PHP中的数据处理”中的任一个操作符,甚至可以是赋值操作符,这是因为赋值操作符要赋的值,可能就是需要判断的值。以上最后一个例子可能有点难以理解,现在让我们再看一个例子:
$int_a = 10;
if ($int_a -= 5)
echo "a = $int_a
";
这些代码将显示
a = 5
该if语句对表达式$int_a -= 5的处理是,$int_a的值先减5,结果值再赋给$int_a。如果结果值为真(即不为零),则执行echo语句。
在这个例子中,除了说明了在只有一个需要执行的语句时,语句段外部的大括号是可选的外,还说明了赋值操作符是可以在if语句中使用的。
提示:即使仅有单个语句时可以不使用大括号,通常还是要使用大括号。这样在以后增加语句时就更加方便。同时也减少了在以后增加语句时忘了添加大括号(这样可能引起细微的逻辑错误)的可能性。
下面的代码将说明else关键字是如何使用的:
$int_a = 5;
if ($int_a -= 5) {
echo "a = $int_a
";
}
else {
echo "a is zero.
";
}
这些代码将显示
a is zero.
elseif关键字按照以下的方法使用:
$str_name = 'John';
if ($str_name == 'Joe') {
echo "Your appointment is on Monday.
";
}
elseif ($str_name == 'John') {
echo "Your appointment is on Wednesday.
";
}
else {
echo "Your appointment is on Firday.
";
}
这些代码将显示:
Your appointment is on Wednesday.
当变量$str_name即不是'Joe',又不是'John'时,将执行if语句的else子语句,否则,将执行其它两个子语句中的一个。通过把错误信息放在else语句块中,以便显示未知的值,else关键字对于捕获未知或未预期的值也非常有用。例如:
if ($str_input == 'A') {
// do A statements.
}
elseif ($str_input == '8') {
// do B statements.
}
else {
echo "Unrecognized Input Error: '$str_input' is unknown.
";
}
在迄今为止所举的例子中,所有if语句的子句中使用的都是同一个的变量。不过,正如下例给出的一个虚构的有关房子和智能型计算机的例子那样,可以充分发挥创造力:
if ($int_left_window_open == 1) {
$int_outside_temperature = check_outside_temperature();
if ($int_outside_temperature close_window('left');
}
}
elseif ($int_right_window_open == 1) {
$bln_mail_exists = look_outside_check_mailbox();
if ($bln_mail_exists) {
make_announcement("The mail is here.');
}
}
else {
$str_window_side = select_side_of_house();
open_window($str_window_side);
}
switch关键字
如果需要同时测试、判断多个条件值时,if语句处理起来就显得比较烦琐--因为所有的elseif语句都要执行过一遍。在这种情况下许多人会发现,使用switch语句会更容易、快速。
switch语句句法结构如下
switch ( VARIABLE ) {
case VALUE1:
break;
case VALUE2:
break;
case VALUEn:
break;
default:
break;
}
在switch语句中,每一个需要检查的值都对应一个相应的case 语句。被检查的变量可以是任意标量值,(也就是说,数字和字符串都可以被检查)。
如果case语句中没有break关键字,那么PHP将执行下一个case语句;如果这个case语句中仍没有break语句,那么就接着执行再下一个case语句,如此下去直至找到break关键字为止。
下面给出一个简短但很完整的例子,讲的是用switch语句来处理命令的命令行程序。每当用户输入一条命令,就会调用switch语句,以决定该执行什么任务。当然,PHP常用于创建Web浏览器程序,可能从来不会这样使用PHP。
switch ($str_input) {
// The print and echo case perform the same task,so
// the print case needs no break keyword.
case 'print':
case 'echo':
// do the echo task.
break;
case 'check_balance':
// do the check balance task.
break;
case 1:
case 2:
// add $str_input to something.
break;
default:
echo "You have entered an unrecognized command or are ";
echo "trying to add a number other than 1 or 2.";
break;
}
使用分支语句的限制是,只能对一个变量进行判断。从另一角度看,这种限制刚好就是switch语句比if语句容易让人理解的原因。
循环语句:
循环语句就是根据程序需要,重复执行一段程序直到一个指定的表达式值为真或假为止。
PHP中有三个控制程序循环的关键字,分别是for,while和do,且这三个关键字处理的循环语句又有细微的差别。但是,无论哪种请况,表达式值都是用来决定循环语句何时应该停止的。使用关键字for的循环语句最为复杂,让我们首先来看它。
for关键字:
从句法结构讲,for语句是由三个表达式和一段语句组成的。形式如下:
for (INITIALIZATION; CONDITION; OPERATION) {
// statement block
}
在循环语句开始之前,首先需要对表达式进行初始化。此时的初始化适用于任意变量,但大多数编程者只对循环语句段中要用到的变量进行初始化。初始化工作可以在for语句之前进行,之所以在for语句内部执行对表达式的初始化工作,是为了有助于生成一自我完备的程序。
提示:初始化表达式通常是赋值表达式。注意在初始化赋值时,不要将等于操作符(==)和赋值操作符(=)搞混淆了。否则,这将会在程序中留下隐患。例如:$iindex == 0就是错误的,正确的表达式应该是$iindex = 0。
条件表达式用于控制循环部分是继续执行,还是停止循环。当条件表达式值判断为假时(就是说为零),则循环终止。
循环变量是条件表达式中使用的变量,用于控制循环什么时候结束。
运算表达式用于在每次执行完循环内部的代码段以后,以某种方式修改在条件表达式中使用的变量(即循环变量)值。
for语句的最基本使用方法就是从零开始计算,直到某一值为止。例如:
for ($loop_variable = 0;
$loop_variable $loop_variable++) {
echo "Inside Loop: loop_variable = $loop_variable
";
}
该语句显示了从0到99的数字:
Inside Loop: loop_variable = 0
Inside Loop: loop_variable = 1
...
Inside Loop: loop_variable = 98
Inside Loop: loop_variable = 99
当循环语句结束时,变量$loop_variable值为100,但这个值不再显示出来,这是因为打印完99以后,又对表达式进行加一运算,得到的变量值为100。这时,判断条件表达式值为假,循环结束。
注意:很关键的一点是,运算表达式(或语句段中的代码)必须要改变循环变量的值,或使用本章稍后讲到的break关键字。否则,循环语句将永远不会结束而成为一死循环。
for循环语句也可以通过对表达式进行递减运算来减小循环变量值:
for ($loop_variable = 100;
$loop_variable $loop_variable --) {
echo "Inside Loop: loop_variable = $loop_variable
";
}
该语句执行后会输出从100到1的数字:
Inside Loop: loop_variable = 100
Inside Loop: loop_variable = 99
...
Inside Loop: loop_variable = 2
Inside Loop: loop_variable = 1
在初始化表达式中能通过逗号隔开的方法对多个变量进行初始化赋值,下例给出了如何对多个变量初始化,以及怎么在一个循环语句中再包含另一个循环语句
for ($row = 0;$row for ($col_value = 0, $col = 0; $col $col_value += $row + $col;
echo "[$row,$col] = $col_value
";
}
}
显示输出为:
[0,0] = 0
[0,1] = 1
[0,2] = 3
[1,0] = 0
...
[2,1] = 5
[2,2] = 9
每次启动内部循环时,$col_calue就会重新初始化为零。
迄今为止,我们只讲了循环变量递加一或递减一的情况。然而,运算表达式是十分灵活的,可以按需要以任何方式改变循环变量值,也可以通过用逗号隔开的办法同时进行多个操作。例如:
$int_number_of_items = 10;
// The following for loop places each
// expression in the loop header on a separate
// line to enhance readability.
For ($first_time = 1,$index =1;
$index $index += 2, $first_time = 0
) {
if ($first_time) {
echo "Report Header
";
}
each "Report Line $index
";
}
if (! $first_time) {
echo "
Report Footer
";
}
代码行输出显示如下:
Report Line 1
Report Line 3
Report Line 4
Report Line 5
Report Line 9
Report Footer
注意,每重复一次循环以后,循环变量($index)会递增2。另外,变量$first_time控制报告的页眉和页脚的输出。
如果改变变量$int_number_of_items的初始值为零的话,那么什么也不会显示出来。第一次对条件表达式值进行判断时,变量$index值为1,变量$int_number_of_item值为0,所以不会进入语句段,也不执行运算表达式。这导致变量$first_time值仍是1,在循环结束时,也不会输出报告的页脚。
while关键字:
当条件为真时,while循环重复一段语句块。如果条件在执行while语句时不为真,语句块就不会被执行。
while循环的语法如下
1.
while ( CONDITION ) {
// statement block.
}
2.
while ( CONDITION ) :
// statement block.
Endwhile;
以下例子显示了使用while语句是如何简单:
$iindex = 0;
while ( $iindex echo "inside while statement: $iindex
";
$iindex++;
endwhile;
echo "outside while statement: $iindex
";
此例子结果将显示
inside while statement: 0
inside while statement: 1
inside while statement: 2
inside while statement: 3
inside while statement: 4
outside while statement: 5
注意当while语句完成以后,$iindex的值为5 -- 而不是条件表达式($iindex )中所希望的4。当$iindex为4时,条件表达式为真,将执行语句块,然后$iindex值赋予5,这时条件语句再次执行,而表达式为假,语句结束。
如果$iindex有大于5的值时(随便说一个数,8),当运行到while语句时,以上的例子将显示
outside while statement: 8
do关键字:
当表达式为假时,do循环执行语句块。此语句的测试条件正好和while循环相反,while循环测试表达式是否为真,并且条件表达式是在语句块执行后测试,而不是在语句块前测试,这也是do循环和while循环的不同点,这意味着语句块至少执行一次。
do循环的语法如下
do {
// statement block
} ( CONDITION );
几乎所有的循环都可以用while语句或者do语句来表示。喜欢怎样表达程序的逻辑结构,觉得哪种方法使用起来更顺手,都无关紧要。有时,使用do print_the_page while the number of pages is less than 20这样表述比while the number of page is less than 20的表述更易于理解。
以下do语句是本章较早使用while表述例子的另一个版本。
$iindex = 0;
do {
echo "Inside Do Statement: $iindex
";
$iindex++;
} while ($iindex echo "Outside Do Statement: $iindex
";
此例子的结果将显示
Inside Do Statement: 0
Inside Do Statement: 1
Inside Do Statement: 2
Inside Do Statement: 3
Inside Do Statement: 4
Outside Do Statement: 5
象while