PHP7语言结构——控制流程

简介

任何PHP脚本都是由一系列语句构成的,一条语句可以是一个赋值语句,一个函数调用,一个循环,一个条件语句,甚至是一个什么也不做的空语句。
语句通常以分号结束。
还可以使用花括号将一组语句封装成一个语句组。
语句组本身也可以当做是一行语句。
PHP中的控制结构分三类:

  • 顺序控制结构
  • 条件控制结构
  • 循环控制结构

顺序控制结构语句是从上到下依次执行的,是PHP中最简单的结构。

条件控制结构

单一条件分支结构(if语句)

语法格式:

if(expr){
    statement;
}

如果表达式expr值为true,php将执行statement,如果值为false,将忽略statement。
单一条件分支结构流程图如下:

T
F
开始
判断条件
程序块
结束

if 语句可以无限层地嵌套在其它 if 语句中,这给程序的不同部分的条件执行提供了充分的弹性。

双向条件分支结构(if…else语句)

语法格式:

if(expr){
    statement1;
}else{
    statement2;
}

如果条件表达式expr值为真,则执行statement1,否则执行statement2.
流程图如下:

T
F
开始
条件
程序块1
程序块2
结束

多向条件分支结构(elseif语句)

语法格式:

if (expr1) {
	statement1;
}elseif (expr2) {
	statement2;
}...
else{
	statement3;
}...

在同一个 if 语句中可以有多个 elseif 部分,其中第一个表达式值为 TRUE(如果有的话)的 elseif 部分将会执行。
执行流程如下:

T
F
T
F
T
F
T
开始
条件1
程序块1
条件2
程序块2
...
...
条件n
程序块n
结束

多向条件分支结构(switch)语句

switch 语句类似于具有同一个表达式的一系列 if 语句。
语法格式:

<?php
switch (条件判断语句) {
	case 可能判断结果a:
		命令执行语句;
		break;
	case 可能判断结果b:
		命令执行语句;
		break;
	...
	default:
		命令执行语句;
?>

switch 语句一行接一行地执行(实际上是语句接语句)。开始时没有代码被执行。仅当一个 case 语句中的值和 switch 表达式的值匹配时 PHP 才开始执行语句,直到 switch 的程序段结束或者遇到第一个 break 语句为止。如果不在 case 的语句段最后写上 break 的话,PHP 将继续执行下一个 case 中的语句段。

switch语句流程控制执行如图:
在这里插入图片描述

在 switch 语句中条件只求值一次并用来和每个 case 语句比较。在 elseif 语句中条件会再次求值。如果条件比一个简单的比较要复杂得多或者在一个很多次的循环中,那么用 switch 语句可能会快一些。

在一个 case 中的语句也可以为空,这样只不过将控制转移到了下一个 case 中的语句。

【示例】

<?php
switch ($i) {
	case 0:
	case 1:
	case 2:
		echo "i is less than 3 but not negative";
		break;
	case 3:
		echo "i is 3";
}
?>

一个 case 的特例是 default。它匹配了任何和其它 case 都不匹配的情况。

【示例】

<?php
switch ($i) {
    case 0:
        echo "i equals 0";
        break;
    case 1:
        echo "i equals 1";
        break;
    case 2:
        echo "i equals 2";
        break;
    default:
        echo "i is not equal to 0, 1 or 2";
}
?>

case 表达式可以是任何求值为简单类型的表达式,即整型或浮点数以及字符串。不能用数组或对象,除非它们被解除引用成为简单类型。

循环控制结构

while循环语句

语法格式:

while (expr)
    statement;

只要 while 表达式的值为 TRUE 就重复执行嵌套中的循环语句。表达式的值在每次开始循环时检查,所以即使这个值在循环语句中改变了,语句也不会停止执行,直到本次循环结束。有时候如果 while 表达式的值一开始就是 FALSE,则循环语句一次都不会执行。

循环语句控制流程图如下:

在这里插入图片描述

do…while循环语句

do-while 循环和 while 循环非常相似,区别在于表达式的值是在每次循环结束时检查而不是开始时。和一般的 while 循环主要的区别是 do-while 的循环语句保证会执行一次(表达式的真值在每次循环结束后检查),然而在一般的 while 循环中就不一定了(表达式真值在循环开始时检查,如果一开始就为 FALSE 则整个循环立即终止)。

语法格式:

do{
	statement;
}while (condition)

do…while循环语句控制流程如图
在这里插入图片描述

for循环

语法格式:

for(expr1; expr2; expr3)
{
	statement;
}

第一个表达式(expr1)在循环开始前无条件求值(并执行)一次。
expr2在每次循环开始前求值。如果值为 TRUE,则继续循环,执行嵌套的循环语句。如果值为 FALSE,则终止循环。
expr3 在每次循环之后被求值(并执行)。

每个表达式都可以为空或包括逗号分隔的多个表达式。表达式expr2中,所有用逗号分隔的表达式都会计算,但只取最后一个结果。expr2为空意味着将无限循环

for循环语句流程控制如图:

F
T
开始
expr1
expr2
结束
statement
expr3

foreach语句

foreach 语法结构提供了遍历数组的简单方式。foreach 仅能够应用于数组和对象,如果尝试应用于其他数据类型的变量,或者未初始化的变量将发出错误信息。有两种语法:

foreach (array_expression as $value)
	statement;
	
foreach (array_expression as $key => $value)
	statement;

第一种格式遍历给定的 array_expression 数组。每次循环中,当前单元的值被赋给 $value 并且数组内部的指针向前移一步(因此下一次循环中将会得到下一个单元)。

第二种格式做同样的事,只除了当前单元的键名也会在每次循环中被赋给变量 $key。

当 foreach 开始执行时,数组内部的指针会自动指向第一个单元。这意味着不需要在 foreach 循环之前调用 reset()。
由于 foreach 依赖内部数组指针,在循环中修改其值将可能导致意外的行为。

可以很容易地通过在 $value 之前加上 & 来修改数组的元素。此方法将以引用赋值而不是拷贝一个值。
【示例】

<?php
$arr = array(1, 2, 3, 4);
foreach ($arr as &$value) {
	$value = $value * 2;
}
// $arr 现在的值为array(2, 4, 6, 8)
var_dump($arr);
unset($value);		// 解除引用
?>

$value 的引用仅在被遍历的数组可以被引用时才可用(例如是个变量)。以下代码则无法运行:

<?php
foreach (array(1, 2, 3, 4) as &$value) {
	$value = $value * 2;
}
?>

foreach 不支持用"@"来抑制错误信息的能力。

用list给嵌套数组解包

(PHP 5 >= 5.5.0, PHP 7)

PHP 5.5 增添了遍历一个数组的数组的功能并且把嵌套的数组解包到循环变量中,只需将 list() 作为值提供。
【示例】

<?php
$array = [
	[1, 2],
	[3, 4],
];

foreach ($array as list($a, $b)) {
	// $a 包含子数组中第一个元素的值
	// $b 包含子数组中第二个元素的值
	echo "A: $a; B: $b\n";
}
?>

list() 中的单元可以少于嵌套数组的,此时多出来的数组单元将被忽略,如果 list() 中列出的单元多于嵌套数组则会发出一条消息级别的错误信息。

流程控制的替代语法

(PHP 4, PHP 5, PHP 7)

PHP 提供了一些流程控制的替代语法,包括 if,while,for,foreach 和 switch。替代语法的基本形式是把左花括号({)换成冒号(:),把右花括号(})分别换成 endif;,endwhile;,endfor;,endforeach; 以及 endswitch;。

【示例】

<?php
if ($a == 5):
	echo "A is equal to 5";
endif;	
?>

替代语法同样可以用在 else 和 elseif 中。下面是一个包括 elseif 和 else 的 if 结构用替代语法格式写的例子:

<?php
if ($a == 5):
	echo "a equals 5";
	echo "...";
elseif ($a == 6):
	echo "a equals 6";
	echo "!!!";
else:
	echo "a is neither 5 or 6";
endif;
?>

不支持在同一个控制块内混合使用两种语法。

switch 和第一个 case 之间的任何输出(含空格)将导致语法错误。

break/continue语句

break 结束当前 for,foreach,while,do-while 或者 switch 结构的执行。

break 可以接受一个可选的数字参数来决定跳出几重循环。
【示例】

<?php
$arr = array
('one', 'two', 'three', 'four', 'stop', 'five');

while (list (, $val) = each($arr)) {
    if ($val == 'stop') {
        break;    
      /* You could also write 'break 1;' here. */
    }
    echo "$val<br />\n";
}
/* 使用可选参数 */
$i = 0;
while (++$i) {
    switch ($i) {
    case 5:
        echo "At 5<br />\n";
        break 1;  /* 只退出 switch. */
    case 10:
        echo "At 10; quitting<br />\n";
        break 2;  /* 退出 switch 和 while 循环 */
    default:
        break;
    }
}?> 

continue 在循环结构用用来跳过本次循环中剩余的代码并在条件求值为真时开始执行下一次循环。

continue 接受一个可选的数字参数来决定跳过几重循环到循环结尾。默认值是 1,即跳到当前循环末尾。
【示例】

<?php
while (list ($key, $value) = each($arr)) {
    if (!($key % 2)) { // skip odd members
        continue;
    }
    do_something_odd($value);
}

$i = 0;
while ($i++ < 5) {
    echo "Outer<br />\n";
    while (1) {
        echo "Middle<br />\n";
        while (1) {
            echo "Inner<br />\n";
            continue 3;
        }
        echo "This never gets output.<br />\n";
    }
    echo "Neither does this.<br />\n";
}
?>   

文件包含

如果想让自定义的函数被多个文件使用,可以将自定义函数组织到一个或者多个文件中,然后使用require()和include()等函数将函数库载入脚本程序中。

require和include

include 语句包含并运行指定文件。

被包含文件先按参数给出的路径寻找,如果没有给出目录(只有文件名)时则按照 include_path 指定的目录寻找。如果在 include_path 下没找到该文件则 include 最后才在调用脚本文件所在的目录和当前工作目录下寻找。如果最后仍未找到文件则 include 结构会发出一条警告;这一点和 require 不同,后者会发出一个致命错误。

如果定义了路径——不管是绝对路径(在Windows下以盘符或者\开头,在Unix/Linux下以/开头)还是当前目录的相对路径(以.或者…开头)——include_path都会被完全忽略。如一个文件以…/开头,则解析器会在当前目录的父目录下寻找该文件。

当一个文件被包含时,其中所包含的代码继承了include所在行的变量范围。从该处开始,调用文件在该行处可用的任何变量在被调用的文件中也都可用。不过所有在包含文件中定义的函数和类都具有全局作用域。

来看一个例子
vars.php

<?php
$color = 'green';
$fruit = 'apple';
?>

test.php

<?php
echo "A $color $fruit";		//A

include 'vars.php';

echo "A $color $fruit";		// A green apple
?>

如果 include 出现于调用文件中的一个函数里,则被调用的文件中所包含的所有代码将表现得如同它们是在该函数内部定义的一样。所以它将遵循该函数的变量范围。此规则的一个例外是魔术常量,它们是在发生包含之前就已被解析器处理的。
【函数中的包含示例】

<?php
function foo() {
	global $color;
	include 'vars.php';
	echo "A $color $fruit";
}
/* vars.php 包含在函数的作用域内,因此$fruit
* 在函数范围外不可用,而$color可用是因为我们
* 将它声明为了全局变量.
*/
foo();		// A green apple
echo "A $color $fruit";		//A green
?>

以上代码输出为:

A green apple
Notice: Undefined variable: fruit in test.php on line 12
A green

当一个文件被包含时,语法解析器在目标文件的开头脱离 PHP 模式并进入 HTML 模式,到文件结尾处恢复。由于此原因,目标文件中需要作为 PHP 代码执行的任何代码都必须被包括在有效的 PHP 起始和结束标记之中。

如果URL include wrappers选项在PHP配置文件中被设置为true,则可以通过URL(通过HTTP或其他支持的封装协议)而不是本地文件来指定要被包含的文件。如果目标服务器将目标文件作为PHP代码解释,则可以用使用于HTTP GET的URL请求字符串来向被包含的文件传递变量。严格的说这和包含一个文件并继承父文件的变量空间不一样,该脚本文件实际上已经在远程服务器上运行了,而本地脚本则包括了其结果。

安全警告
远程文件可能会经远程服务器处理(根据文件后缀以及远程服务器是否在运行PHP而定),但必须产生出一个合法的PHP脚本,因为其将被本地服务器处理。如果来自盐城服务器的文件应该在远端运行而至输出结果,那么用readfile()函数更好。另外要格外小心以确保远程的脚本产生出合法并且是所需的代码。

在失败时 include 返回 FALSE 并且发出警告。成功的包含则返回 1,除非在包含文件中另外给出了返回值。可以在被包括的文件中使用 return 语句来终止该文件中程序的执行并返回调用它的脚本。同样也可以从被包含的文件中返回值。可以像普通函数一样获得 include 调用的返回值。不过这在包含远程文件时却不行,除非远程文件的输出具有合法的 PHP 开始和结束标记(如同任何本地文件一样)。可以在标记内定义所需的变量,该变量在文件被包含的位置之后就可用了。

因为 include 是一个特殊的语言结构,其参数不需要括号。在比较其返回值时要注意。

如果在包含文件中定义有函数,这些函数不管是在 return 之前还是之后定义的,都可以独立在主文件中使用。如果文件被包含两次,PHP 5 发出致命错误因为函数已经被定义,但是 PHP 4 不会对在 return 之后定义的函数报错。推荐使用 include_once 而不是检查文件是否已包含并在包含文件中有条件返回。

要在脚本中自动包含文件,可以在php.ini中的 auto_prepend_file 和 auto_append_file 配置选项。


require 和 include 几乎完全一样,除了处理失败的方式不同之外。require 在出错时产生 E_COMPILE_ERROR 级别的错误。

因此,如果遇到文件丢失时需要继续运行,则使用include,如果想停止处理页面,则使用require。

include_once和require_once

include_once 语句在脚本执行期间包含并运行指定文件。此行为和 include 语句类似,唯一区别是如果该文件中已经被包含过,则不会再次包含。如同此语句名字暗示的那样,只会包含一次。

include_once 可以用于在脚本执行期间同一个文件有可能被包含超过一次的情况下,想确保它只被包含一次以避免函数重定义,变量重新赋值等问题。

require_once 语句和 require 语句完全相同,唯一区别是 PHP 会检查该文件是否已经被包含过,如果是则不会再次包含。

goto语句

(PHP 5>=5.30, PHP7)
goto操作符可以用来跳转到程序中的另一位置。该目标位置可以用目标名称加上冒号来标记,而跳转指令是goto之后街上目标位置的标记。PHP中的goto有一定限制,目标位置只能位于同一个文件和作用域,也就是说,无法跳出一个函数或类方法,也无法跳入到另一个函数。也无法跳入到任何循环或switch结构中。可以跳出循环或者switch,通常的用法是用goto代替多层break。
【示例】

<?php
goto a;
echo 'Foo';

a:
echo 'Bar';
?>

以上程序输出为:

Bar
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章