2009年07月21日

PHPの配列結合演算子+(プラス)について考えてみた

PHPには配列結合演算子というものがあります。

名前結果
$a + $b結合$a および $b を結合する。

この「+」演算子は、連想配列に関して言えば、オブジェクト指向で言うところの「継承」に相当するものだと最近気がつきました。下の例を見てください。

$parent = array(
    "aaa" => 111
   ,"bbb" => 222
);
echo '$parent = ';
print_r($parent);

$child = array(
    "bbb" => 2222
   ,"ccc" => 3333
);
echo '$child = ';
print_r($child);

echo '$child + $parent = ';
print_r($child + $parent);

---実行結果↓---
$parent = Array
(
    [aaa] => 111
    [bbb] => 222
)
$child = Array
(
    [bbb] => 2222
    [ccc] => 3333
)
$child + $parent = Array
(
    [bbb] => 2222
    [ccc] => 3333
    [aaa] => 111
)

childがparentを継承し、parentを上書きまたは拡張していることが分かります。$child + $parent + $grandparent + ... のように、どんどん継承元をつないでいくこともできます。

連想配列が入れ子の場合は少し注意しなければいけません。配列結合演算子は要素が何であろうと親子で重複するものは子供が上書きしてしまいます。

(上と同様なのでコード省略 & 実行結果↓)
$parent = Array
(
    [aaa] => Array
    (
        [abbb] => 222
        [accc] => 333
    )
)
$child = Array
(
    [aaa] => Array
    (
        [abbb] => 2222
    )
)
$child + $parent = Array
(
    [aaa] => Array
    (
        [abbb] => 2222
    )
)

子供の配列が上書きするので、親にあった[accc]が消えてしまいます。入れ子の場合も再帰的に継承したい場合は、自前で関数を書く必要があります。(一通りマニュアルを探しましたが、PHPはこれに相当する演算子や関数を持っていないようでした。)

自前で書くといってもほとんどの機能は+演算子が担ってくれるので、ほんの数行で済みます。

function array_extend(array $child, array $parent)
{
    $child += $parent;
    foreach ($child as $key => &$val) {
        if (is_array($val) && isset($parent[$key]) && is_array($parent[$key])) {
            $val = array_extend($val, $parent[$key]);
        }
    }
    return $child;
}

この関数を使うと入れ子でも再帰的に継承します。

array_extend($child, $parent) = Array
(
    [aaa] => Array
        (
            [abbb] => 2222
            [accc] => 333
        )

)

継承は結合法則が成り立つので、array_extend($a, array_extend($b, $c)) もarray_extend(array_extend($a, $b), $c)も同じ結果が返ってきます。

私の場合、ページのデータファイル(serializeとかJSONとか)を読み込んで順に表示するようなプログラムを書くことが多いので、よく活用しています。継承を使うと、共通部分を親に記述し、子供には差分だけを記述しておけるからです。


ググっていると、+演算子の挙動は直感に反するみたいな記述がされていることも多いようです(私も同感です)が、連想配列に限って使う場合は使いどころがあるのではないでしょうか。

PHPは連想配列と配列の区別がないから、継承演算子なのか結合演算子なのかはっきりせずに実装して、このような挙動になっているのかなと邪推しています。

配列演算と集合演算の違い、SQLのUNIONとの比較とか、まだ考察したいことが色々ありますが、それはまた別の機会で。

参考

posted by Hiraku at 01:36 | Comment(0) | TrackBack(0) | プログラミング | このブログの読者になる | 更新情報をチェックする
この記事へのコメント
コメントを書く
お名前:

メールアドレス:

ホームページアドレス:

コメント:

この記事へのトラックバックURL
http://blog.seesaa.jp/tb/123924280

この記事へのトラックバック