背景
GET/POST リクエストのパラメータやセッション、データベースのデータ等との同期をとるためによく配列のマージを使うが、Hash::merge()
で全部いけるかと思ってたら数値キーはマージされずにどちらも残ってしまい、マージを繰り返すうちに配列の要素がどんどん増えてしまうといった現象が発生してしまっていた。
(参考)
PHP の array_merge() や array_recursive() 等の違いをまとめました | Tips Note
キーが数値型であっても、同じ値のキーについてはマージする配列の値で上書きするようにしたい。
実装
Hash::flatten()
でマージする/される配列を一度1次元配列へと平坦化し、マージして Hash::extend()
で元に戻す。こうすることで、平坦化された配列のキーは(多次元配列であれば)全て文字列キーになるので、上書きマージが可能となる。
コード
public function arr_merge_overwrite( $array1, $array2 ) {
// マージする/される配列を平坦化する
$array1 = Hash::flatten( $array1 );
$array2 = Hash::flatten( $array2 );
// マージ
$return = Hash::merge( $array1, $array2 );
// マージした配列を通常の配列に戻す
return Hash::expand( $return );
}
動作例
// 対象データ
$a = array(
0 => 'blue',
1 => 'red',
'a' => 'cyan',
3 => 'yellow',
);
$b = array(
1 => 'orange',
2 => 'green',
3 => 'purple',
'a' => 'white',
'b' => 'black',
);
// 出力
var_dump( arr_merge_overwrite( $a, $b ) );
// array(
// 0 => 'blue', // $a の値
// 1 => 'orange', // $b の値($a の値をマージ)
// 'a' => 'white', // $b の値($a の値をマージ)
// 3 => 'purple', // $b の値($a の値をマージ)
// 2 => 'green', // $b の値
// 'b' => 'black', // $b の値
// );
余談
CakePHP 以外でも使いたいので、標準の関数のみでうまくやる方法があったら知りたいです。
(愚直なやり方としては flatten(), expand() を移植すればどの環境でもできるが、、、)