@TOC
前言
知其然,也要知其所以然
PHP陣列是什麼?
關於這個問題,官方文件給出了這樣的解釋:
PHP 中的陣列實際上是一個有序對映。對映是一種把 values 關聯到 keys
的型別。此型別在很多方面做了優化,因此可以把它當成真正的陣列,或列表(向量),雜湊表(是對映的一種實現),字典,集合,棧,佇列以及更多可能性。由於陣列元素的值也可以是另一個陣列,樹形結構和多維陣列也是允許的。
值得注意的是,和JAVA、C 等靜態語言不同。在PHP中,初始化陣列的時候不必指定陣列的大小和儲存資料的型別,這既是PHP的優點,也是它的缺點。
PHP陣列如何分類?
通常來講,PHP陣列一般分為 索引陣列 和 關聯陣列 兩類。
當然,你也可以從其他方向分類陣列。如:可以按照陣列維度,分為 一維陣列 和 多維陣列 等。
從陣列的定義中我們可以知道,陣列其實就是鍵值對的有序對映。這也就意味著,陣列中的每一個元素都是以 key => value 的形式存在。當一個陣列中元素的每一個 key 都是數字的時候,那麼這個陣列就稱為 索引陣列 ;反之,如果存在 key 不是數字的陣列就稱為 關聯陣列
遍歷陣列的方式有哪些?
1. for
for 迴圈是 PHP 中最複雜的迴圈結構。它的行為和 C 語言的相似。 for 迴圈的語法是:
for (expr1; expr2; expr3)
statement 第一個表示式(expr1)在迴圈開始前無條件求值(並執行)一次。expr2 在每次迴圈開始前求值。如果值為 TRUE,則繼續迴圈,執行巢狀的迴圈語句。如果值為 FALSE,則終止迴圈。
expr3 在每次迴圈之後被求值(並執行)。
每個表示式都可以為空或包括逗號分隔的多個表示式。表示式 expr2 中,所有用逗號分隔的表示式都會計算,但只取最後一個結果。
值得注意的是:expr2 為空意味著將無限迴圈下去(和 C 一樣,PHP 暗中認為其值為 TRUE)。這可能不像想象中那樣沒有用,因為經常會希望用有條件的 break 語句來結束迴圈而不是用 for 的表示式真值判斷。如:
$arr = ['a','b','c'];
for ($i = 0; ; $i++) {
echo $arr[$i];
if ($arr[$i] === 'c')
break;
}
for迴圈是我們常用的一種遍歷陣列的方式,它可以能方便的對陣列進行遍歷,並運算元組的每一個元素,一個簡單的示例:
$arr = ['a','b','c'];
for ($i = 0; $i < count($arr); $i++) {
echo $arr[$i];
}
這種寫法或許是剛入行的coder最常用的寫法,但是它可能是糟糕的(可能會導致執行很慢)。存在一個問題,每一次迴圈都要使用 count() 函式計算一次陣列 $arr 的長度,由於陣列的長度始終不變,一種更優的方法是先將陣列長度用中間變數儲存起來,而不是多次呼叫 count() ,如下:
$arr = ['a','b','c'];
for ($i = 0, $len = count($arr); $i < $len; $i++) {
echo $arr[$i];
}
另外,PHP 也支援用冒號的 for 迴圈的替代語法。
$arr = ['a','b','c'];
for ($i = 0, $len = count($arr); $i < $len; $i++):
echo $arr[$i];
endfor;
for 迴圈的適用範圍很廣,可以用於索引陣列、關聯陣列,也可用於迴圈字串等……
$arr = [
'a' => 'a',
'b' => 'b',
'c' => 'c'
];
//迴圈列印關聯陣列值
for ($i = 'a', $j = 0; $j <count($arr); $j++, $i = chr(ord($i) + 1) ) {
echo $arr[$i];
}
$str = 'abcdefg';
//依次列印字串元素
for ($i = 0, $len = strlen($str); $i < $len; $i++):
echo $str[$i];
echo "<hr/>";
endfor;
2. foreach
foreach 語法結構提供了遍歷陣列的簡單方式。
foreach 僅能夠應用於陣列和物件,如果嘗試應用於其他資料型別的變數,或者未初始化的變數將發出錯誤資訊。有兩種語法:
foreach (array_expression as $value)
statementforeach (array_expression as $key => $value)
statement
第一種格式遍歷給定的 array_expression 陣列。每次迴圈中,當前單元的值被賦給 $value 並且陣列內部的指標向前移一步(因此下一次迴圈中將會得到下一個單元)。第二種格式做同樣的事,只不過當前單元的鍵名也會在每次迴圈中被賦給變數 $key。
一個簡單的示例:
$arr = [
'a' => 'a',
'b' => 'b',
'c' => 'c'
];
foreach ($arr as $value) {
echo $value;
} //只獲取值
foreach ($arr as $key => $value) {
echo $key;
echo $value;
} //獲取鍵 和 值
如果想在 foreach 內部修改陣列的元素也是可以的,可以很容易地通過在 $value 之前加上 & 來修改陣列的元素。此方法將以引用賦值而不是拷貝一個值。例如:
$arr = [
'a' => 'a',
'b' => 'b',
'c' => 'c'
];
foreach ($arr as &$value) {
$value = $value.'zzz';
} //只獲取值
var_dump($arr); //array(3) { ["a"]=> string(4) "azzz" ["b"]=> string(4) "bzzz" ["c"]=> &string(4) "czzz" }
此處需要注意的是,$value 的引用僅在被遍歷的陣列可以被引用時才可用(例如是個變數)。以下程式碼則無法執行:
foreach (array(1, 2, 3, 4) as &$value) {
$value = $value * 2;
}
*Warning
陣列最後一個元素的 $value 引用在 foreach 迴圈之後仍會保留,建議使用 unset() 來將其銷燬。因為這及其容易造成一些問題,如:foreach 造成的奇怪問題
Note:
當 foreach 開始執行時,陣列內部的指標會自動指向第一個單元。這意味著不需要在 foreach 迴圈之前呼叫 reset()。
由於 foreach 依賴內部陣列指標,在迴圈中修改其值將可能導致意外的行為。
foreach 不支援用“@”來抑制錯誤資訊的能力。
foreach 遍歷物件
值得一提的是,foreach只能遍歷可見的屬性,這意味著在物件外部使用 foreach ,只能訪問 public 型別的屬性。如果需要遍歷 protected型別的屬性,就需要在本類或其子類內部定義方法使用 foreach。而遍歷 private 型別的屬性,則必須在其本類中進行。
3. 使用 list()、each()遍歷陣列
所涉及的函式有:
list() :把陣列中的值賦給一組變數【像 array() 一樣,這不是真正的函式,而是語言結構】
each() :返回陣列中當前的鍵/值對並將陣列指標向前移動一步
reset :將陣列的內部指標指向第一個單元,並返回陣列第一個單元的值,如果陣列為空則返回 FALSE。
示例如下:
$arr = [
'ak' => 'av',
'bk' => 'bv',
'ck' => 'cv'
];
reset($arr); //開始迴圈之前,需呼叫此函式將陣列內部指標指向第一個單元。避免指標為指向第一個單元,造成陣列迴圈不全或迴圈失敗的情況
while (list($k, $v) = each($arr)) {
echo $k.'=>'.$v;
echo "<hr/>";
}
值得注意的事:
1.自PHP7.2.0開始,each() 函式已被棄用。非常不推薦使用此函式。【如在PHP 7.3.4版本中呼叫,會返回錯誤(Deprecated: The each() function is deprecated. This message will be suppressed on further calls in …….)】
2.PHP 5 裡,list() 從最右邊的引數開始賦值; PHP 7 裡,list() 從最左邊的引數開始賦值。如果你用單純的變數,不用擔心這一點。 但是如果你用了具有索引的陣列,通常你期望得到的結果和在 list()
中寫的一樣是從左到右的,但在 PHP 5 裡實際上不是, 它是以相反順序賦值的。
通常而言,不建議依賴於操作的順序,在未來可能會再次發生修改。
4. 使用陣列指標遍歷陣列
所涉及的函式有:
reset :將陣列的內部指標指向第一個單元,並返回陣列第一個單元的值,如果陣列為空則返回 FALSE。
key():函式返回陣列中內部指標指向的當前單元的鍵名。 但它不會移動指標。如果內部指標超過了元素列表尾部,或者陣列是空的,此函式會返回 NULL。
current():current() 函式返回當前被內部指標指向的陣列單元的值,並不移動指標。如果內部指標指向超出了單元列表的末端,current() 返回 FALSE。【值得注意的是,如果陣列某一個元素的值就等於 (bool) false,此函式也會返回 FALSE,所以不能使用此函式判斷是否到陣列末尾】
next():next() 和 current() 的行為類似,只有一點區別,在返回值之前將內部指標向前移動一位。這意味著它返回的是下一個陣列單元的值並將陣列指標向前移動了一位。【同樣,如果陣列某一個元素的值就等於 (bool) false,此函式也會返回 FALSE,所以不能使用此函式判斷是否到陣列末尾】
$arr = [
'ak' => 'av',
'false' => false,
false => 'cv'
];
while (true) {
$k = key($arr);
if (!isset($k)) {
reset($arr); //結束之前應將陣列內部指標指向第一個單元
unset($k);
break;
}
echo $k.'=>'.current($arr);
echo '<hr/>';
next($arr);
}
一些值得注意的事:
1、$arr[true] 等價於 $arr[1];$arr[false] 等價於 $arr[0]。
2、使null做為鍵名,相當於建立或覆蓋一個$arr[null],可以使用$arr[null]或$arr[""]來訪問。
3、使用帶小數點的數字作為鍵名時,鍵名會自動擷取整數部分作為鍵名。如$arr[123.45]=5,你使用$arr[123.45]或$arr[123]均可以取得鍵值;用foreach遍歷時,使用的是$arr[123]。
4、$arr[]=5,會在陣列$arr後面新增上該元素。
本作品採用《CC 協議》,轉載必須註明作者和本文連結