PHP5.2とPHP5.3でArrayObjectの挙動が違う話

ハマッタのでメモ。

<?php

$a = new ArrayObject(array('test' => 1));

print_r($a);

これをPHP5.2とPHP5.3で実行すると以下のようになる

# PHP5.2
ArrayObject Object
(
    [test] => 1
)

# PHP5.3
ArrayObject Object
(
    [storage:ArrayObject:private] => Array
        (
            [test] => 1
        )

)

PHP5.3の場合、なにやらデータの持ち方が新しくなったのかstorage:ArrayObject:privateとか言うのが増えてる。

これはおそらくstorageというprivate変数に配列のデータを持つようになったという感じか。まぁそれ自体は問題ない。

問題は以下のコード

<?php

$a = new ArrayObject(array('test' => 1));
$b = new ArrayObject($a);

print_r($b);

実行結果

# PHP5.2
ArrayObject Object
(
    [test] => 1
)

# PHP5.3
ArrayObject Object
(
    [storage:ArrayObject:private] => ArrayObject Object
        (
            [storage:ArrayObject:private] => Array
                (
                    [test] => 1
                )

        )

)

PHP5.2のときにはArrayObjectにArrayObjectを渡しても配列として処理されていたが、PHP5.3からはArrayObjectがネストされてしまう。

正直ArrayObjectってのは配列をシュミレートするもののはずなのでArrayObjectをオブジェクトとして保存してしまうPHP5.3の仕様には聊か首を捻らざるを得ない。

さらに怖いのが、この状態でもちゃんと配列として動いてしまうのでネストされてることに気付かないということだ。

<?php

$a = new ArrayObject(array('test' => 1));
$b = new ArrayObject($a);

print($b['test']); # ちゃんと「1」と表示される

つまり普通に扱ってる分には配列として動いてくれるので、めちゃくちゃネストしちゃっててもぜんぜん気付かない。

気付いたときには

ArrayObject Object
(
    [storage:ArrayObject:private] => ArrayObject Object
        (
            [storage:ArrayObject:private] => ArrayObject Object
                (
                    [storage:ArrayObject:private] => ArrayObject Object
                        (
                            [storage:ArrayObject:private] => ArrayObject Object
                                (
                                    [storage:ArrayObject:private] => ArrayObject Object
                                        (
                                            [storage:ArrayObject:private] => ArrayObject Object
                                                (
                                                    [storage:ArrayObject:private] => ArrayObject Object
                                                        (
                                                            [storage:ArrayObject:private] => Array
                                                                (
                                                                    [test] => 1
                                                                )

                                                        )

                                                )

                                        )

                                )

                        )

                )

        )

)

こんなことになってるかもしれない。(ってかなってたw)

ArrayObjectを良く使う人はPHP5.3では注意しましょう!

ちなみに解決方法としては色々あるだろうけど、ArrayObjectに渡すときにarrayにキャストするとかしましょう。

<?php

$a = new ArrayObject(array('test' => 1));
$b = new ArrayObject((array)$a); // array型へキャスト