PHP 添字配列・連想配列と array_merge、配列結合演算子 (+) の挙動
array_merge の挙動が添字配列と連想配列で異なることは知られていますが、
- キーが 文字列の数字 である配列
- キーが 0始まりの連番ではない数値 である配列
の場合にどういう挙動をするのかが気になり、調査しました。
array_merge
PHPマニュアルに書かれている仕様は以下の通りです。
入力配列が同じキー文字列を有していた場合、そのキーに関する後に指定された値が、 前の値を上書きします。しかし、配列が同じ添字番号を有していても 値は追記されるため、このようなことは起きません。
入力配列の中にある数値添字要素の添字の数値は、 結果の配列ではゼロから始まる連続した数値に置き換えられます。
つまり、添字配列の場合はキーが振り直され、連想配列の場合は同一キー後勝ちです。
**調査の結果、キーが 文字列の数字 であっても、キーが 0始まりの連番ではない数値 であっても、添字配列と同じ挙動で、キーは連番で振り直されました。
**
配列結合演算子 (+)
PHPマニュアルに書かれている仕様は以下の通りです。
- 演算子は、右側の配列を左側の配列に追加したものを返します。 両方の配列に存在するキーについては左側の配列の要素が優先され、 右側の配列にあった同じキーの要素は無視されます。
つまり、添字配列か連想配列かを問わず、同一キー先勝ちです。
調査の結果、キーが 文字列の数字 の場合、添字配列と同じ挙動、というよりキーが数値にキャストされた上で処理されていました。
補足
キーのキャストについては、ちゃんとPHPマニュアルに書いてありました。
つまり、array_merge や演算子の仕様ではなく、
配列を生成した時点で、すでにキャストされているということのようです。
10 進数の int として妥当な形式の String は、 数値の前に + 記号がついていない限り、 int 型にキャストされます。 つまり、キーに "8" を指定すると、実際には 8 として格納されるということです。一方 "08" はキャストされません。これは十進数として妥当な形式ではないからです。
floats もまた int にキャストされます。つまり、 小数部分は切り捨てられるということです。たとえばキーに 8.7 を指定すると、実際には 8 として格納されます。
bool も int にキャストされます。つまり、 キーに true を指定すると実際には 1 に格納され、 同様にキーを false とすると実際には 0 となります。
Null は空文字列にキャストされます。つまり、キーに null を指定すると、実際には "" として格納されます。
調査コード
$a = [
'A-1',
'A-2',
'A-3',
];
$b = [
'B-1',
'B-2',
'B-3',
];
$c = [
1 => 'C-1',
2 => 'C-2',
3 => 'C-3',
];
$d = [
'0' => 'D-1',
'1' => 'D-2',
'2' => 'D-3',
];
$e = [
'first' => 'E-1',
'second' => 'E-2',
'third' => 'E-3',
];
var_dump(array_merge($a, $b));
/*
array(6) {
[0] => string(3) "A-1"
[1] => string(3) "A-2"
[2] => string(3) "A-3"
[3] => string(3) "B-1"
[4] => string(3) "B-2"
[5] => string(3) "B-3"
}
*/
var_dump(array_merge($a, $c));
/*
array(6) {
[0] => string(3) "A-1"
[1] => string(3) "A-2"
[2] => string(3) "A-3"
[3] => string(3) "C-1"
[4] => string(3) "C-2"
[5] => string(3) "C-3"
}
*/
var_dump(array_merge($a, $d));
/*
array(6) {
[0] => string(3) "A-1"
[1] => string(3) "A-2"
[2] => string(3) "A-3"
[3] => string(3) "D-1"
[4] => string(3) "D-2"
[5] => string(3) "D-3"
}
*/
var_dump(array_merge($a, $e));
/*
array(6) {
[0] => string(3) "A-1"
[1] => string(3) "A-2"
[2] => string(3) "A-3"
'first' =>
string(3) "E-1"
'second' =>
string(3) "E-2"
'third' =>
string(3) "E-3"
}*/
var_dump(array_merge($c, $d));
/*
array(6) {
[0] => string(3) "C-1"
[1] => string(3) "C-2"
[2] => string(3) "C-3"
[3] => string(3) "D-1"
[4] => string(3) "D-2"
[5] => string(3) "D-3"
}
*/
var_dump(array_merge($c, $e));
/*
array(6) {
[0] => string(3) "C-1"
[1] => string(3) "C-2"
[2] => string(3) "C-3"
'first' => string(3) "E-1"
'second' => string(3) "E-2"
'third' => string(3) "E-3"
}
*/
var_dump(array_merge($d, $e));
/*
array(6) {
[0] => string(3) "D-1"
[1] => string(3) "D-2"
[2] => string(3) "D-3"
'first' => string(3) "E-1"
'second' => string(3) "E-2"
'third' => string(3) "E-3"
}
*/
var_dump(array_merge($a, $b, $e));
/*
array(9) {
[0] => string(3) "A-1"
[1] => string(3) "A-2"
[2] => string(3) "A-3"
[3] => string(3) "B-1"
[4] => string(3) "B-2"
[5] => string(3) "B-3"
'first' => string(3) "E-1"
'second' => string(3) "E-2"
'third' => string(3) "E-3"
}
*/
var_dump($a + $b);
/*
array(3) {
[0] => string(3) "A-1"
[1] => string(3) "A-2"
[2] => string(3) "A-3"
}
*/
var_dump($a + $c);
/*
array(4) {
[0] => string(3) "A-1"
[1] => string(3) "A-2"
[2] => string(3) "A-3"
[3] => string(3) "C-3"
}
*/
var_dump($a + $d);
/*
array(3) {
[0] => string(3) "A-1"
[1] => string(3) "A-2"
[2] => string(3) "A-3"
}
*/
var_dump($a + $e);
/*
array(6) {
[0] => string(3) "A-1"
[1] => string(3) "A-2"
[2] => string(3) "A-3"
'first' => string(3) "E-1"
'second' => string(3) "E-2"
'third' => string(3) "E-3"
}
*/
var_dump($c + $d);
/*
array(4) {
[1] => string(3) "C-1"
[2] => string(3) "C-2"
[3] => string(3) "C-3"
[0] => string(3) "D-1"
}
*/
var_dump($c + $e);
/*
array(6) {
[1] => string(3) "C-1"
[2] => string(3) "C-2"
[3] => string(3) "C-3"
'first' => string(3) "E-1"
'second' => string(3) "E-2"
'third' => string(3) "E-3"
}
*/
var_dump($d + $e);
/*
array(6) {
[0] => string(3) "D-1"
[1] => string(3) "D-2"
[2] => string(3) "D-3"
'first' => string(3) "E-1"
'second' => string(3) "E-2"
'third' => string(3) "E-3"
}
*/
var_dump($a + $b + $e);
/*
array(6) {
[0] => string(3) "A-1"
[1] => string(3) "A-2"
[2] => string(3) "A-3"
'first' => string(3) "E-1"
'second' => string(3) "E-2"
'third' => string(3) "E-3"
}
*/
Discussion