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