## Array 數組(復合)
PHP中的數組實際上是一個有序映射。映射是一種把values關聯到keys的類型。此類型在很多方面做了優化,因此可以把它當成真正的數組,或列表(向量),散列表(是映射的一種實現),字典,集合,棧,隊列以及更多可能性。由于數組元素的值也可以是另一個數組,樹型結構和多維數組也是允許的。
解釋這些結構超出了本手冊的范圍,但對于每種結構至少會提供一個例子。要得到這些結構的更多信息,建議參考有關此廣闊主體的其他著作。
### 語法
#### 定義數組 [array()](http://php.net/manual/zh/function.array.php)
可以用 [array()](http://php.net/manual/zh/function.array.php) 語言結構來新建一個數組。它接受任意數量用逗號分隔的 \*鍵(key) => 值(value)\*對。
~~~
array( key => value
, ...
)
// 鍵(key)可是是一個整數 integer 或字符串 string
// 值(value)可以是任意類型的值
~~~
最后一個數組單元之后的逗號可以省略。通常用于單行數組定義中,例如常用 *array(1, 2)* 而不是 *array(1, 2, )*。對多行數組定義通常保留最后一個逗號,這樣要添加一個新單元時更方便。
自 5.4 起可以使用短數組定義語法,用 *\[\]* 替代 *array()*。
**Example #1 一個簡單數組**
```
<?php
$array?=?array(
????"foo"?=>?"bar",
????"bar"?=>?"foo",
);
//?自?PHP?5.4?起
$array?=?[
????"foo"?=>?"bar",
????"bar"?=>?"foo",
];
?>
```
key可以是integer或者string。value可以是任意類型。
array分類:
1.索引數組(以數組為下標)
如:$arr\[2\]
2.關聯數組(以字符串為下標)
如:$arr\["aa"\]
此外key會有如下的強制轉換:
* 包含有合法整型值的字符串會被轉換為整型。例如鍵名“8”實際會被存儲為8。但是“08”則不會強制轉換,因為其不是一個合法 的十進制數值。
* 浮點數也會被轉換為整型,意味著其小數部分會被舍去。例如鍵名8.7實際會被儲存為8。
* 布爾值也會被轉換成整型。即鍵值true實際會被 儲存為1而鍵名false會被儲存為0。
* null會被轉換為空字符串,即鍵名null實際會 被儲存為“”。
* 數組和對象不能被用為鍵名。堅持這么做會導致警告:illegal offset type。
如果在數組定義中多個單元都使用了同一個鍵名,則只使用了最后一個,之前的都被覆蓋了。
**Example #2 類型強制與覆蓋示例**
```
`<?php
$array?=?array(
????1????=>?"a",
????"1"??=>?"b",
????1.5??=>?"c",
????true?=>?"d",
);
var_dump($array);
?>`
```
以上此例會輸出:
```
~~~
array(1) {
[1]=>
string(1) "d"
}
~~~
```
上例中所有的鍵名都被強制轉換為 *1*,則每一個新單元都會覆蓋前一個的值,最后剩下的只有一個 *"d"*。
PHP 數組可以同時含有 [integer](http://php.net/manual/zh/language.types.integer.php) 和 [string](http://php.net/manual/zh/language.types.string.php) 類型的鍵名,因為 PHP 實際并不區分索引數組和關聯數組。
如果對給出的值沒有指定鍵名,則取當前最大的整數索引值,而新的鍵名將是該值加一。如果指定的鍵名已經有了值,則該值會被覆蓋。
**Example #3 混合 **[**integer**](http://php.net/manual/zh/language.types.integer.php)** 和 **[**string**](http://php.net/manual/zh/language.types.string.php)** 鍵名**
```
<?php
$array = array(
"foo" => "bar",
"bar" => "foo",
100 => -100,
-100 => 100,
);
var_dump($array);
```
以上例會輸出:
~~~
array(4) {
["foo"]=>
string(3) "bar"
["bar"]=>
string(3) "foo"
[100]=>
int(-100)
[-100]=>
int(100)
}
~~~
key 為可選項。如果未指定,PHP 將自動使用之前用過的最大 [integer](http://php.net/manual/zh/language.types.integer.php) 鍵名加上 1 作為新的鍵名。
**Example #4 沒有鍵名的索引數組**
```
<?php
$array?=?array("foo",?"bar",?"hallo",?"world");
var_dump($array);
?>
```
以上例程會輸出:
~~~
array(4) {
[0]=>
string(3) "foo"
[1]=>
string(3) "bar"
[2]=>
string(5) "hallo"
[3]=>
string(5) "world"
}
~~~
還可以只對某些單元指定鍵名而對其它的空置:
**Example #5 僅對部分單元指定鍵名**
```
<?php
$array?=?array(
?????????"a",
?????????"b",
????6?=>?"c",
?????????"d",
);
var_dump($array);
?>
```
以上例程會輸出:
~~~
array(4) {
[0]=>
string(1) "a"
[1]=>
string(1) "b"
[6]=>
string(1) "c"
[7]=>
string(1) "d"
}
~~~
可以看到最后一個值 *"d"* 被自動賦予了鍵名 *7*。這是由于之前最大的整數鍵名是 *6*。
#### 用方括號語法訪問數組單元
數組單元可以通過 *array\[key\]* 語法來訪問。方括號和花括號可以互換使用來訪問數組單元(例如 $array\[42\] 和 $array{42} 在上例中效果相同)。
**Example #6 訪問數組單元**
```
<?php
$array?=?array(
????"foo"?=>?"bar",
????42????=>?24,
????"multi"?=>?array(
?????????"dimensional"?=>?array(
?????????????"array"?=>?"foo"
?????????)
????)
);
var_dump($array["foo"]);
var_dump($array[42]);
var_dump($array["multi"]["dimensional"]["array"]);
?>
```
自 PHP 5.4 起可以用直接對函數或方法調用的結果進行數組解引用,在此之前只能通過一個臨時變量。
自 PHP 5.5 起可以直接對一個數組原型進行數組解引用。
**Example #7 數組解引用**
```
<?php
function?getArray()?{
????return?array(1,?2,?3);
}
//?on?PHP?5.4
$secondElement?=?getArray()[1];
//?previously
$tmp?=?getArray();
$secondElement?=?$tmp[1];
//?or
list(,?$secondElement)?=?getArray();
?>
```
> **Note**:
> 試圖訪問一個未定義的數組鍵名與訪問任何未定義變量一樣:會導致 **`E_NOTICE**` 級別錯誤信息,其結果為 **`NULL**`。
#### 用方括號的語法新建/修改
可以通過明示地設定其中的值來修改一個已有數組。
這是通過在方括號內指定鍵名來給數組賦值實現的。也可以省略鍵名,在這種情況下給變量名加上一對空的方括號(*\[\]*)。
~~~
$arr[key] = value;
$arr[] = value;
// key 可以是 integer 或 string
// value 可以是任意類型的值
~~~
如果 $arr 還不存在,將會新建一個,這也是另一種新建數組的方法。不過并不鼓勵這樣做,因為如果 $arr 已經包含有值(例如來自請求變量的 [string](http://php.net/manual/zh/language.types.string.php))則此值會保留而 *\[\]* 實際上代表著[字符串訪問運算符](http://php.net/manual/zh/language.types.string.php#language.types.string.substr)。初始化變量的最好方式是直接給其賦值。。
要修改某個值,通過其鍵名給該單元賦一個新值。要刪除某鍵值對,對其調用 [unset()](http://php.net/manual/zh/function.unset.php) 函數。
```
<?php
$arr?=?array(5?=>?1,?12?=>?2);
$arr[]?=?56;????//?This?is?the?same?as?$arr[13]?=?56;
????????????????//?at?this?point?of?the?script
$arr["x"]?=?42;?//?This?adds?a?new?element?to
????????????????//?the?array?with?key?"x"
????????????????
unset($arr[5]);?//?This?removes?the?element?from?the?array
unset($arr);????//?This?deletes?the?whole?array
?>
```
> **Note**:
> 如上所述,如果給出方括號但沒有指定鍵名,則取當前最大整數索引值,新的鍵名將是該值加上 1(但是最小為 0)。如果當前還沒有整數索引,則鍵名將為 *0*。
> 注意這里所使用的最大整數鍵名*不一定*當前就在數組中。它只要在上次數組重新生成索引后曾經存在過就行了。以下面的例子來說明:
```
<?php
//?創建一個簡單的數組
$array?=?array(1,?2,?3,?4,?5);
print_r($array);
//?現在刪除其中的所有元素,但保持數組本身不變:
foreach?($array?as?$i?=>?$value)?{
????unset($array[$i]);
}
print_r($array);
//?添加一個單元(注意新的鍵名是?5,而不是你可能以為的?0)
$array[]?=?6;
print_r($array);
//?重新索引:
$array?=?array_values($array);
$array[]?=?7;
print_r($array);
?>
```
以上例程會輸出:
~~~
Array
(
[0] => 1
[1] => 2
[2] => 3
[3] => 4
[4] => 5
)
Array
(
)
Array
(
[5] => 6
)
Array
(
[0] => 6
[1] => 7
)
~~~
### 實用函數
有很多操作數組的函數,參見[數組函數](http://php.net/manual/zh/ref.array.php)一節。
> **Note**:
> [unset()](http://php.net/manual/zh/function.unset.php) 函數允許刪除數組中的某個鍵。但要注意數組將*不會*重建索引。如果需要刪除后重建索引,可以用 [array\_values()](http://php.net/manual/zh/function.array-values.php) 函數。
```
<?php
$a?=?array(1?=>?'one',?2?=>?'two',?3?=>?'three');
unset($a[2]);
/*?will?produce?an?array?that?would?have?been?defined?as
???$a?=?array(1?=>?'one',?3?=>?'three');
???and?NOT
???$a?=?array(1?=>?'one',?2?=>'three');
*/
$b?=?array_values($a);
//?Now?$b?is?array(0?=>?'one',?1?=>'three')
?>
```
[foreach](http://php.net/manual/zh/control-structures.foreach.php) 控制結構是專門用于數組的。它提供了一個簡單的方法來遍歷數組。
### 數組做什么和不做什么
#### 為什么 *$foo\[bar\]* 錯了?
應該始終在用字符串表示的數組索引上加上引號。例如用 *$foo\['bar'\]* 而不是 *$foo\[bar\]*。但是為什么呢?可能在老的腳本中見過如下語法:
```
<?php
$foo[bar]?=?'enemy';
echo?$foo[bar];
//?etc
?>
```
這樣是錯的,但可以正常運行。那么為什么錯了呢?原因是此代碼中有一個未定義的常量(bar)而不是字符串('bar'-注意引號),而 PHP 可能會在以后定義此常量,不幸的是你的代碼中有同樣的名字。它能運行,是因為 PHP 自動將*裸字符串*(沒有引號的字符串且不對應于任何已知符號)轉換成一個其值為該裸字符串的正常字符串。例如,如果沒有常量定義為 **`bar**`,PHP 將把它替代為 *'bar'* 并使用之。
**Note**: 這并不意味著*總是*給鍵名加上引號。用不著給鍵名為[常量](http://php.net/manual/zh/language.constants.php)或[變量](http://php.net/manual/zh/language.variables.php)的加上引號,否則會使 PHP 不能解析它們。
```
<?php
error_reporting(E_ALL);
ini_set('display_errors',?true);
ini_set('html_errors',?false);
//?Simple?array:
$array?=?array(1,?2);
$count?=?count($array);
for?($i?=?0;?$i?<?$count;?$i++)?{
????echo?"\nChecking?$i:?\n";
????echo?"Bad:?"?.?$array['$i']?.?"\n";
????echo?"Good:?"?.?$array[$i]?.?"\n";
????echo?"Bad:?{$array['$i']}\n";
????echo?"Good:?{$array[$i]}\n";
}
?>
```
以上例程會輸出:
~~~
Checking 0:
Notice: Undefined index: $i in /path/to/script.html on line 9
Bad:
Good: 1
Notice: Undefined index: $i in /path/to/script.html on line 11
Bad:
Good: 1
Checking 1:
Notice: Undefined index: $i in /path/to/script.html on line 9
Bad:
Good: 2
Notice: Undefined index: $i in /path/to/script.html on line 11
Bad:
Good: 2
~~~
### 轉換為數組
對于任意 [integer](http://php.net/manual/zh/language.types.integer.php),[float](http://php.net/manual/zh/language.types.float.php),[string](http://php.net/manual/zh/language.types.string.php),[boolean](http://php.net/manual/zh/language.types.boolean.php) 和 [resource](http://php.net/manual/zh/language.types.resource.php) 類型,如果將一個值轉換為數組,將得到一個僅有一個元素的數組,其下標為 0,該元素即為此標量的值。換句話說,*(array)$scalarValue* 與 *array($scalarValue)* 完全一樣。
如果一個 [object](http://php.net/manual/zh/language.types.object.php) 類型轉換為 [array](http://php.net/manual/zh/language.types.array.php),則結果為一個數組,其單元為該對象的屬性。鍵名將為成員變量名,不過有幾點例外:整數屬性不可訪問;私有變量前會加上類名作前綴;保護變量前會加上一個 '\*' 做前綴。這些前綴的前后都各有一個 NULL 字符。這會導致一些不可預知的行為:
```
<?php
class?A?{
????private?$A;?//?This?will?become?'\0A\0A'
}
class?B?extends?A?{
????private?$A;?//?This?will?become?'\0B\0A'
????public?$AA;?//?This?will?become?'AA'
}
var_dump((array)?new?B());
?>
```
上例會有兩個鍵名為 'AA',不過其中一個實際上是 '\\0A\\0A'。
將 **`NULL**` 轉換為 [array](http://php.net/manual/zh/language.types.array.php) 會得到一個空的數組。
### 比較
可以用 [array\_diff()](http://php.net/manual/zh/function.array-diff.php) 和[數組運算符](http://php.net/manual/zh/language.operators.array.php)來比較數組。
**Example #8 使用 array()**
```
<?php
//?Array?as?(property-)map
$map?=?array(?'version'????=>?4,
??????????????'OS'?????????=>?'Linux',
??????????????'lang'???????=>?'english',
??????????????'short_tags'?=>?true
????????????);
????????????
//?strictly?numerical?keys
$array?=?array(?7,
????????????????8,
????????????????0,
????????????????156,
????????????????-10
??????????????);
//?this?is?the?same?as?array(0?=>?7,?1?=>?8,?...)
$switching?=?array(?????????10,?//?key?=?0
????????????????????5????=>??6,
????????????????????3????=>??7,?
????????????????????'a'??=>??4,
????????????????????????????11,?//?key?=?6?(maximum?of?integer-indices?was?5)
????????????????????'8'??=>??2,?//?key?=?8?(integer!)
????????????????????'02'?=>?77,?//?key?=?'02'
????????????????????0????=>?12??//?the?value?10?will?be?overwritten?by?12
??????????????????);
??????????????????
//?empty?array
$empty?=?array();?????????
?>
```
**Example #9 集合**
```
`<?php
$colors?=?array('red',?'blue',?'green',?'yellow');
foreach?($colors?as?$color)?{
????echo?"Do?you?like?$color?\n";
}
?>`
```
**Example #10 在循環中改變單元**
```
<?php
//?PHP?5
foreach?($colors?as?&$color)?{
????$color?=?strtoupper($color);
}
unset($color);?/*?ensure?that?following?writes?to
$color?will?not?modify?the?last?array?element?*/
//?Workaround?for?older?versions
foreach?($colors?as?$key?=>?$color)?{
????$colors[$key]?=?strtoupper($color);
}
print_r($colors);
?>
```
以上例程會輸出:
~~~
Array
(
[0] => RED
[1] => BLUE
[2] => GREEN
[3] => YELLOW
)
~~~
本例生成一個下標從 1 開始的數組。
**Example #11 下標從 1 開始的數組**
```
<?php
$firstquarter??=?array(1?=>?'January',?'February',?'March');
print_r($firstquarter);
?>
```
以上例程會輸出:
~~~
Array
(
[1] => 'January'
[2] => 'February'
[3] => 'March'
)
~~~
**Example #12 填充數組**
```
<?php
//?fill?an?array?with?all?items?from?a?directory
$handle?=?opendir('.');
while?(false?!==?($file?=?readdir($handle)))?{
????$files[]?=?$file;
}
closedir($handle);?
?>
```
數組是有序的。也可以使用不同的排序函數來改變順序。更多信息參見[數組函數](http://php.net/manual/zh/ref.array.php)。可以用 [count()](http://php.net/manual/zh/function.count.php) 函數來數出數組中元素的個數。
**Example #13 數組排序**
```
<?php
sort($files);
print_r($files);
?>
```
因為數組中的值可以為任意值,也可是另一個數組。這樣可以產生遞歸或多維數組。
**Example #14 遞歸和多維數組**
```
<?php
$fruits?=?array?(?"fruits"??=>?array?(?"a"?=>?"orange",
???????????????????????????????????????"b"?=>?"banana",
???????????????????????????????????????"c"?=>?"apple"
?????????????????????????????????????),
??????????????????"numbers"?=>?array?(?1,
???????????????????????????????????????2,
???????????????????????????????????????3,
???????????????????????????????????????4,
???????????????????????????????????????5,
???????????????????????????????????????6
?????????????????????????????????????),
??????????????????"holes"???=>?array?(??????"first",
???????????????????????????????????????5?=>?"second",
????????????????????????????????????????????"third"
?????????????????????????????????????)
????????????????);
//?Some?examples?to?address?values?in?the?array?above?
echo?$fruits["holes"][5];????//?prints?"second"
echo?$fruits["fruits"]["a"];?//?prints?"orange"
unset($fruits["holes"][0]);??//?remove?"first"
//?Create?a?new?multi-dimensional?array
$juices["apple"]["green"]?=?"good";?
?>
```
數組(Array) 的賦值總是會涉及到值的拷貝。使用[引用運算符](http://php.net/manual/zh/language.operators.php)通過引用來拷貝數組。
```
<?php
$arr1?=?array(2,?3);
$arr2?=?$arr1;
$arr2[]?=?4;?//?$arr2?is?changed,
?????????????//?$arr1?is?still?array(2,?3)
?????????????
$arr3?=?&$arr1;
$arr3[]?=?4;?//?now?$arr1?and?$arr3?are?the?same
?>
```
- 序言
- 簡介
- PHP是什么?
- PHP能做什么?
- 基本語法
- 類型
- boolean(布爾型)
- integer(整型)
- float(浮點型)
- string(字符串)
- array(數組)
- object(對象)
- callable(可調用)
- resource(資源)
- NULL(無類型)
- 偽類型
- 類型轉換的判別
- 變量
- 基礎
- 預定義變量
- 變量范圍
- 可變變量
- 來自PHP之外的變量
- 常量
- 語法
- 魔術常量
- 表達式
- 運算符
- 運算符優先級
- 算術運算符
- 賦值運算符
- 位運算符
- 比較運算符
- 錯誤控制運算符
- 執行運算符
- 遞增/遞減運算符
- 邏輯運算符
- 字符串運算符
- 數組運算符
- 類型運算符
- 流程控制
- if
- else
- elseif/else if
- 流程控制的替代語法
- while
- do-whille
- for
- foreach
- break
- continue
- switch
- declare
- return
- require
- include
- require_once
- include_once
- goto
- 函數
- 用戶自定義函數
- 函數的參數
- 返回值
- 可變函數
- 內部 (內置)函數
- 匿名函數
- 類與對象
- 簡介
- 基本概念
- 屬性
- 類的自動加載
- 構造函數
- 訪問控制(可見性)