|
配列
PHP の配列は、実際には順番付けられたマップです。マップは型の一種で、
値をキーに関連付けます。
この型は、さまざまな使い道にあわせて最適化されます。
配列としてだけでなく、リスト (ベクター)、
ハッシュテーブル (マップの実装の一つ)、辞書、コレクション、スタック、
キュー等として使用することが可能です。
PHP の配列には他の PHP 配列を値として保持することができるため、
非常に簡単にツリー構造を表現することが可能です。
これらのデータ構造に関する説明は本マニュアルの範囲を超えるので省略しますが、
各々について、少なくとも一つは例を示します。
この分野は広範囲にまたがり、さまざまな文献が存在します。
より詳細な情報については、それらの文献を参照ください。
構文
array で指定
配列 は、言語に組み込まれた
array で作成することが可能です。この構造は、
特定の数のカンマで区切られた
キー => 値 の組を引数とします。
array(
key => value,
key2 => value2,
key3 => value3,
...
)
最後の要素のあとのカンマは、書いても書かなくてもかまいません。
配列を一行で定義する場合は、ふつうは最後のカンマを省略します。つまり、
array(1, 2) のほうが
array(1, 2, ) よりおすすめだということです。
しかし複数行で定義する場合は、最後のカンマをつけることが一般的です。
そうしておけば、配列の最後に要素を追加するのが容易になるからです。
注意:
array() を []
で置き換えることが出来る、配列の短縮構文も使えます。
例1 シンプルな配列定義
<?php
$array = array(
"foo" => "bar",
"bar" => "foo",
);
// 配列の短縮構文
$array = [
"foo" => "bar",
"bar" => "foo",
];
?>
key は、整数 または
文字列です。
value には任意の型を指定できます。
さらに、次のような key のキャストが発生します。
-
10 進数の int として妥当な形式の String は、
数値の前に
+ 記号がついていない限り、
int 型にキャストされます。
つまり、キーに "8" を指定すると、実際には
8 として格納されるということです。一方 "08"
はキャストされません。これは十進数として妥当な形式ではないからです。
-
floats もまた int にキャストされます。つまり、
小数部分は切り捨てられるということです。たとえばキーに
8.7 を指定すると、実際には
8 として格納されます。
-
bool も int にキャストされます。つまり、
キーに
true を指定すると実際には 1 に格納され、
同様にキーを false とすると実際には 0 となります。
-
Null は空文字列にキャストされます。つまり、キーに
null を指定すると、実際には "" として格納されます。
-
array や object は、キーとして使えません。
キーとして使おうとすると
Illegal offset type という警告が発生します。
配列の宣言時に同じキーで複数の要素を指定すると、
最後に指定したものがそれまでの値を上書きします。
例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 においては添字配列と連想配列の間に違いはなく、配列型は 1 つだけで、
同じ配列で整数のインデックスと文字列のインデックスを同時に使えます。
例3 整数と文字列のキーの混在例
<?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
はこれまでに使われた整数のキーの中で最大のものに 1 を加えた値を使います。
例4 数値添字配列でキーを省略する例
<?php
$array = array("foo", "bar", "hello", "world");
var_dump($array);
?>
array(4) {
[0]=>
string(3) "foo"
[1]=>
string(3) "bar"
[2]=>
string(5) "hello"
[3]=>
string(5) "world"
}
一部の要素にだけキーを指定することもできます。
例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 だからです。
例6 複雑な型のキャストと上書きの例
以下の例は、型のキャストされた時と、要素が上書きされる時の全ての場合を示しています。
<?php
$array = array(
1 => 'a',
'1' => 'b', // 値 "a" は "b" で上書きされます。
1.5 => 'c', // 値 "b" は "c" で上書きされます。
-1 => 'd',
'01' => 'e', // この値は数値文字列ではないので、キー1を上書きしません
'1.5' => 'f', // この値は数値文字列ではないので、キー1を上書きしません
true => 'g', // 値 "c" は "g" で上書きされます。
false => 'h',
'' => 'i',
null => 'j', // 値 "i" は "j" で上書きされます。
'k', // 値 "k" にはキー2が割り当てられます。なぜなら、これより前のキーの最大値は1だからです。
2 => 'l', // 値 "k" は "l" で上書きされます。
);
var_dump($array);
?>
array(7) {
[1]=>
string(1) "g"
[-1]=>
string(1) "d"
["01"]=>
string(1) "e"
["1.5"]=>
string(1) "f"
[0]=>
string(1) "h"
[""]=>
string(1) "j"
[2]=>
string(1) "l"
}
角括弧構文による配列要素へのアクセス
配列の要素へのアクセスには array[key] 構文を使います。
例7 配列の要素へのアクセス
<?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"]);
?>
string(3) "bar"
int(24)
string(3) "foo"
注意:
PHP 8.0.0 より前のバージョンでは、
配列の要素にアクセスするときに、
角括弧と波括弧がどちらも同じ意味で使えていました。
(つまり、この例で $array[42] と $array{42}
は同じものを表しているということです)。
波括弧で配列にアクセスする文法は、
PHP 7.4.0 以降は非推奨になり、
PHP 8.0.0 以降はサポートされなくなっています。
例8 配列のデリファレンス
<?php
function getArray() {
return array(1, 2, 3);
}
$secondElement = getArray()[1];
?>
注意:
配列に定義されていないキーへアクセスしたときの挙動は、
未定義の変数にアクセスしたときと同じです。
つまり、E_WARNING レベルの警告
(PHP 8.0.0 より前のバージョンでは E_NOTICE )
が発生し、結果が null になります。
注意:
配列で文字列以外のスカラー値をデリファレンスした場合は、
返される結果は null となります。
PHP 7.4.0 より前のバージョンでは、何もエラーは発生しませんでした。
PHP 7.4.0 以降では、E_NOTICE が発生します。
PHP 8.0.0 以降では、E_WARNING が発生します。
角括弧構文で作成/修正
明示的に値を設定することにより、既存の配列を修正することも可能です。
これは、角括弧の中にキーを指定し、配列に値を代入することにより行います。
キーを省略することも可能です。この場合、空の角括弧
("[] ") の変数名として追加してください。
$arr[キー] = 値;
$arr[] = 値;
// キー は 文字列 または
// 整数のどちらかです。
// 値 の型は、何でもかまいません。
$arr がまだ存在しない場合、
あるいは null や false に設定されている場合は、
新しく配列を作成します。
つまり、これは配列を作成する方法のひとつでもあります。
とはいえ、この方法を使うことはおすすめしません。なぜなら、既に
$arr に何らかの値
(リクエスト変数からの文字列など) が入っている場合にはその値がそのまま残り、
[] が実際には
文字列アクセス演算子
を表してしまうからです。
変数を初期化するときには、直接代入するほうがよいでしょう。
注意:
PHP 7.1.0 以降では、文字列に空のインデックス演算子を適用すると
fatal エラーが発生するようになりました。
これまでのバージョンではエラーにならず、文字列が配列に変換されていました。
注意:
PHP 8.1.0 以降では、
false に設定している値から新しく配列を作成することは推奨されません。
null や未定義の値から配列を新しく作成することはまだ許可されています。
ある値を変更するには、
新しい値に値を代入します。特定のキー/値の組を削除したい場合には、
unset を使用する必要があります。
注意:
上記のように、キーを省略して新規要素を追加する場合、
追加される数値添字は、使用されている添字の最大値 +1 (ただし、少なくとも 0 以上) になります。
まだ数値添字が存在しない場合は、添字は 0
(ゼロ) となります。
警告
PHP 4.3.0 以降、上記のような添字生成動作は変更されました。
現在では、配列に追加する際に、
その配列の最大添字が負である場合は次の添え字はゼロ
(0 ) となります。
以前は、正の添字の場合と同様に新しい添字は最大添字に +1
したものがセットされました。
次のキー生成において、オフセットとして使われる整数値
(添字の最大値) に対応するエントリーが、
必ずしも配列内に存在するわけではないことに注意してください。
しかし、その値は、多くの場合、
配列にある整数のキー値の最大値と等しいはずです。以下に例を示します。
配列の分解
配列は、言語構造 [] (PHP 7.1.0 以降)
または、list を使って分解することができます。
これらの言語構造は、
配列を個別の値に分解する用途に使えます。
これは、多次元配列を foreach で反復処理しながら分解する用途に使えます。
変数が与えられない配列の要素は無視されます。
配列の分解は、常にインデックス 0 から始まります。
PHP 7.1.0 以降では、
連想配列も分解できるようになりました。
数値をキーとした配列の右側の要素を、
インデックスを明示的に指定することで簡単に選択できるようになっています。
配列の分解を使うと、2つの変数を簡単に入れ替えることができます。
注意:
分解時に値を代入する際には、... 演算子はサポートされていません。
注意:
定義されていない配列のキーにアクセスしようとすると、
未定義の変数にアクセスする場合と同じ扱いになります。
つまり、E_WARNING レベルの警告
(PHP 8.0.0 より前のバージョンでは E_NOTICE )
が発生し、結果が null になります。
有用な関数
配列で使用する便利な関数がたくさんあります。
配列関数 の節を参照ください。
注意:
unset関数は配列のキーを削除することが出来ます。
ただし、これによってインデックスの再構築が行われるわけではないことに
注意してください。
"通常の整数添字" (0 から始まり、1 つずつ増加) のみを使用している場合、
array_values
を用いてインデックスを再構築することができます。
配列専用の制御構造として foreach があります。
この構造は、配列の要素に簡単に連続的にアクセスする手段を提供します。
配列ですべきこととしてはならないこと
なぜ、$foo[bar] は使用できないのか?
連想配列の添字の前後は常に引用符で括る必要があります。
例えば、$foo[bar] ではなく $foo['bar'] を使用してください。
しかし、$foo[bar] はなぜ誤りなのでしょうか?
古いスクリプトで次のような構文を見たことがあるかもしれません。
これは間違っていますが、動作します。では、なぜ間違っているのでしょう?
それは、このコードには文字列 ('bar' - 引用符で括られている)
ではなく未定義の定数 (bar ) が使用されているためです。
下位互換性の維持のため、未定義の定数は同じ名前の文字列に自動的に変換されます。
そのため、このコードは動作します。
例えば、bar という名前の定義されていない定数があるとすると、
PHP は 'bar' という文字列でそれを置換して使用します。
警告
生の文字列を未定義の定数として扱う振る舞いは、
E_NOTICE
レベルの警告が発生します。
この振る舞いは PHP 7.2.0 以降は推奨されなくなり、
E_WARNING レベルの警告が発生します。
PHP 8.0.0 以降は、この振る舞いは削除され、
Error 例外がスローされるようになっています。
注意:
これは、添字を常にクォートするという意味ではありません。
定数や
変数
を添字として使う際には、クォートしてしまうと PHP
はそれを解釈できなくなってしまいます。
上の例の出力は以下となります。
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
この具体例を以下に示します。
error_reporting で
(E_ALL を指定する等により)
E_NOTICE レベルのエラー出力を有効にした場合、
上記のエラーが出力されます。
デフォルトでは、
error_reporting はこれらを表示しない設定になっています。
構文の節に記述したように、角括弧
('[ ' および '] ')
の間には、式がなければなりません。これは、
次のように書くことが可能であることを意味します。
これは、関数の戻り値を配列の添字として使用する例です。PHP
は定数についても認識します。以下のような E_*
の使用例を見たことがあるかもしれません。
最初の例の bar と全く同様に
E_ERROR も有効な添字であることに注意してください。
しかし、実際には最後の例は次のように書くことと同じです。
これは、E_ERROR が 1
と等しいこと等によります。
では、なぜ $foo[bar] は動作することが可能なのでしょう?
それは、bar が定数式であることを
期待される構文で使用されているためです。しかし、この場合、
bar という名前の定数は存在しません。PHP は、
この場合、あなたが文字列"bar" のようにリテラル
bar を指定したが引用符を忘れたと仮定します。
では、なぜ間違っているのでしょう?
将来的に、PHP 開発チームが他の定数またはキーワードを追加したいと思うかもしれず、
問題となる可能性があります。例えば、現在でも、
単語 empty および
default を使用することはできません。
これは、これらが特別な
予約済みのキーワードであるためです。
注意:
二重引用符で括られた文字列の中では
引用符で配列の添字を括らないことができ、このため、
"$foo[bar]" は有効です。
この理由の詳細については、上記の例や
文字列中での変数のパースを参照ください。
配列への変換
int, float, string,
bool, resourceのいずれの型においても、
array に変換する場合、
最初のスカラー値が割り当てられている一つの要素 (添字は 0)
を持つ配列を得ることになります。
言い換えると、(array) $scalarValue
は、array($scalarValue) と全く同じです。
objectを配列にする場合には、配列の要素として
オブジェクトの属性 (メンバ変数) を持つ配列を得ることになります。
添字はメンバ変数名となりますが、いくつか注意すべき例外があります。
整数のプロパティはアクセス不能になります。
private 変数の場合、変数名の頭にクラス名がつきます。また、
protected 変数の場合は、変数名の頭に '*' がつきます。
このとき、頭に追加される値の前後に NUL バイトがついてきます。
未初期化の
型付きプロパティ は黙って捨てられます。
これらの NUL バイトは、以下のような予期せぬ振る舞いをすることがあります:
上の例では 'AA' というキーがふたつあるように見えますが、
そのうちひとつは、実際は '\0A\0A' ということになります。
null を配列に変換すると、空の配列を得ます。
比較
array_diff と
配列演算子
を用いると、配列を比較することができます。
配列のアンパック
配列の前に ... を付けると、
配列を定義する際に、その配列の値を展開(アンパック)させることができます。
配列と、Traversable
を実装したオブジェクトを展開させることができます。
... を使った配列のアンパックは、
PHP 7.4.0 以降で利用可能です。
配列のアンパックは、配列中で何度でも行うことができます。
... の前後に通常の要素を置くこともできます:
例9 簡単な配列のアンパック
<?php
// 配列の短縮構文を使っています。
// array() 記法も使えます。
$arr1 = [1, 2, 3];
$arr2 = [...$arr1]; //[1, 2, 3]
$arr3 = [0, ...$arr1]; //[0, 1, 2, 3]
$arr4 = [...$arr1, ...$arr2, 111]; //[1, 2, 3, 1, 2, 3, 111]
$arr5 = [...$arr1, ...$arr1]; //[1, 2, 3, 1, 2, 3]
function getArr() {
return ['a', 'b'];
}
$arr6 = [...getArr(), 'c' => 'd']; //['a', 'b', 'c' => 'd']
?>
... を使ったアンパックの動作は、
array_merge 関数の仕様に従います。
つまり、キーが文字列の場合は後に指定された値が前の値を上書きしますし、
キーが整数の場合は、ゼロから値が振り直されます:
例10 キーが重複した場合の配列のアンパック
<?php
// キーが文字列の場合
$arr1 = ["a" => 1];
$arr2 = ["a" => 2];
$arr3 = ["a" => 0, ...$arr1, ...$arr2];
var_dump($arr3); // ["a" => 2]
// キーが整数の場合
$arr4 = [1, 2, 3];
$arr5 = [4, 5, 6];
$arr6 = [...$arr4, ...$arr5];
var_dump($arr6); // [1, 2, 3, 4, 5, 6]
// $arr6 は、 [0 => 1, 1 => 2, 2 => 3, 3 => 4, 4 => 5, 5 => 6] と同義です。
// ここでは、キーの値は保存されません。
?>
注意:
キーが整数でも文字列でもない場合は、
TypeError がスローされます。
そのようなキーを持つ値は、
Traversable
オブジェクト経由でしか生成できません。
注意:
PHP 8.1 より前のバージョンでは、
キーが文字列の場合に、アンパックをサポートしていませんでした:
例
PHP の配列型は、いろいろな使い方ができます。配列の強力な機能を示すため、
ここでいくつかの例を紹介します。
例11 array() の使用例
<?php
// マップを行う配列
$map = array( 'version' => 4,
'OS' => 'Linux',
'lang' => 'english',
'short_tags' => true
);
// 数値キーのみを有する
$array = array( 7,
8,
0,
156,
-10
);
// これは、array( 0 => 7, 1 => 8, ...) と同じです
$switching = array( 10, // key = 0
5 => 6,
3 => 7,
'a' => 4,
11, // key = 6 (最大の添字は5です)
'8' => 2, // key = 8 (整数!)
'02' => 77, // key = '02'
0 => 12 // 値10は12で上書きされます
);
// 空の配列
$empty = array();
?>
例12 コレクション
<?php
$colors = array('red', 'blue', 'green', 'yellow');
foreach ($colors as $color) {
echo "Do you like $color?\n";
}
?>
Do you like red?
Do you like blue?
Do you like green?
Do you like yellow?
配列を参照渡しすることでその値を直接変更できます。
例13 ループ内での要素の変更
<?php
foreach ($colors as &$color) {
$color = mb_strtoupper($color);
}
unset($color); /* これ以降の $color への書き込みが
配列の要素を書き換えてしまわないことを保証する */
print_r($colors);
?>
Array
(
[0] => RED
[1] => BLUE
[2] => GREEN
[3] => YELLOW
)
この例は、1 から始まる配列を作成します。
例14 1 から始まる添字
<?php
$firstquarter = array(1 => 'January', 'February', 'March');
print_r($firstquarter);
?>
Array
(
[1] => 'January'
[2] => 'February'
[3] => 'March'
)
例15 配列に代入する
<?php
// ディレクトリから全てのアイテムを配列に代入する
$handle = opendir('.');
while (false !== ($file = readdir($handle))) {
$files[] = $file;
}
closedir($handle);
?>
配列には順番が付けられます。異なったソート関数を用いて順番を変更することも可能です。
より詳細な情報については、配列関数 を参照ください。
count 関数を使用することで、
配列の要素数を数えることが可能です。
例16 配列のソート
<?php
sort($files);
print_r($files);
?>
配列の値は何でも良いため、その値を他の配列とすることも可能です。
これにより、再帰的な配列や多次元の配列を作成することが可能です。
例17 再帰および多次元配列
<?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"
)
);
// 上の配列の内容を取得するための例
echo $fruits["holes"][5]; // "second" を表示します
echo $fruits["fruits"]["a"]; // "orange" を表示します
unset($fruits["holes"][0]); // "first" を削除します
// 新しい多次元配列を作成します
$juices["apple"]["green"] = "good";
?>
配列への代入においては、常に値がコピーされることに注意してください。
配列をリファレンスでコピーする場合には、
リファレンス演算子を使う必要があります。
|