matsuo

PHP の array_merge() や array_recursive() 等の違いをまとめました

以前、JavaScript でのオブジェクトのマージについてまとめましたが、
今回は似たような話で PHP の配列のマージについてまとめます。

PHP の配列のマージ方法には大きく3つあり、

  • "+" 演算子
  • array_merge() 関数
  • array_merge_recursive() 関数

あと、個人的に CakePHP をよく使っているので

  • CakePHP の Hash::merge() メソッド

この4つの方法について、挙動の違いを調べました。


一次元配列

実際にコードを動かしてみて、2つの配列をマージした結果を見てみます。
対象データはこちら。

<?php
// 対象データ
$a = array(
    0 => 'blue',
   1 => 'red',
    'a' => 'cyan',
   3 => 'yellow',
);

$b = array(
    1 => 'orange',
 2 => 'green',
  3 => 'purple',
 'a' => 'white',
  'b' => 'black',
);

 

+演算子 の場合

$result = $a + $b;

// 結果
array (
  0 => 'blue',
   1 => 'red',
    'a' => 'cyan',
   3 => 'yellow',
 2 => 'green',
  'b' => 'black',
)

$a に $b を足しています。
$a の内容は、そっくりそのまま残りました。
$b の内容のうち、$a に存在しない添字の値が追加されています。
同じ添字のものは、$a の値が優先されるということになります。
 

array_merge() の場合

$result = array_merge($a, $b);

// 結果
array (
    0 => 'blue',
   1 => 'red',
    'a' => 'white',
  2 => 'yellow',
 3 => 'orange',
 4 => 'green',
  5 => 'purple',
 'b' => 'black',
)

添字が文字列の場合と数字の場合とで処理が異なるのでややこしい。
添字が文字列の場合は、同じ添字があれば $b の値で上書きされます。$b 優先。
添字が数字の値はすべてマージされ、上書きされることはありません。
このとき、添字の数字は0から順番に振り直されています。
 

array_merge_recursive の場合

$result = array_merge_recursive($a, $b);

// 結果
array (
  0 => 'blue',
   1 => 'red',
    'a' => array (
     0 => 'cyan',
       1 => 'white',
  ),
  2 => 'yellow',
 3 => 'orange',
 4 => 'green',
  5 => 'purple',
 'b' => 'black',
)

添字が文字列の場合は、上書きせずに結果を配列化しています。
添字が数字の場合は、array_merge() と同じです。
 

CakePHP Hash::merge() の場合

$result = Hash::merge($a, $b);

// 結果
array (
   0 => 'blue',
   1 => 'red',
    'a' => 'white',
  3 => 'yellow',
 4 => 'orange',
 2 => 'green',
  5 => 'purple',
 'b' => 'black',
)

$a と同じ添字があれば $b の値で上書きされます。$b 優先。
添字が数字でも文字列と同じ挙動で、順番に振り直されることはありません。
個人的には、いちばん直感的な気がします。
 

 

二次元配列

二次元配列の場合も調べてみました。
ちょっと長くなるのでややこしく見えますが、当然ながら一次元配列のときと同じルールでマージされています。
対象データはこちら。

<?php
// 対象データ
$a = array(
   'a' => array(
      'blue',
       'red',
    ),
  1 => array(
      'green',
  ),
);

$b = array(
 'a' => array(
      'yellow',
 ),
  1 => array(
      'orange',
 ),
  2 => array(
      'purple',
 )
);

 

+演算子 の場合

$result = $a + $b;

// 結果
array (
   'a' => array (
     0 => 'blue',
       1 => 'red',
    ),
  1 => array (
     0 => 'green',
  ),
  2 => array (
     0 => 'purple',
 ),
)

$a の値はそっくりそのまま残ります。
$b の値は、$a にない添字のものだけが残ります。
 

array_merge() の場合

$result = array_merge($a, $b);

// 結果
array (
  'a' => array (
     0 => 'yellow',
 ),
  0 => array (
     0 => 'green',
  ),
  1 => array (
     0 => 'orange',
 ),
  2 => array (
     0 => 'purple',
 ),
)

添字が文字列 → $b の値で上書きされます。
添字が数字 → 上書きされず、すべて残ります(添字は 0 から順に振り直される)。
 

array_merge_recursive() の場合

$result = array_merge_recursive($a, $b);

// 結果
array (
  'a' =>  array (
        0 => 'blue',
       1 => 'red',
        2 => 'yellow',
 ),
  0 => array (
     0 => 'green',
  ),
  1 => array (
     0 => 'orange',
 ),
  2 => array (
     0 => 'purple',
 ),
)

添字が文字列 → 結果は配列としてマージされます。
添字が数字 → 上書きされず、すべて残ります(添字は 0 から順に振り直される)。
 

CakePHP Hash::merge() の場合

$result = Hash::merge($a, $b);

// 結果
array (
   'a' => array (
     0 => 'blue',
       1 => 'red',
        2 => 'yellow',
 ),
  1 => array (
     0 => 'green',
      1 => 'orange',
 ),
  2 => array (
     0 => 'purple',
 ),
)

添字が数字・文字列にかかわらず、結果は配列としてマージされます。
 

 

まとめ

  • "+" 演算子は、左側の値を優先。
  • array_merge() と array_merge_recursive() は、添字が文字列の場合と数字の場合とで動きが違うから気をつけよう。
  • CakePHP の Hash::merge() べんり。
お問い合わせはこちら