y_uti のブログ

統計、機械学習、自然言語処理などに興味を持つエンジニアの技術ブログです

PHP の array と Traversable

PHP の foreach に配列ではない値を渡すと、警告が出力されます。次のような test.php というスクリプトを作成して確認します。

<?php
$arr = null;
foreach ($arr as $k => $v) {
    print "$k => $v\n";
}

これを実行すると、次のような警告が出力されました。

$ php test.php
PHP Warning:  Invalid argument supplied for foreach() in /.../test.php on line 3

foreach に渡される配列が null かもしれない場合、配列にキャストするというテクニックがあるようです。以下のようにすると警告が出力されなくなります。

<?php
$arr = null;
foreach ((array) $arr as $k => $v) {
    print "$k => $v\n";
}

これは、null を配列にキャストすると空の配列になるためです。PHP での配列へのキャストについては以下に記載されています。
PHP: 配列 - Manual

一方で、PHP の foreach には、通常の配列のほかに Traversable インタフェースを実装したオブジェクトを渡すこともできます。Traversable を実装したクラスには、SPL の各種コンテナやジェネレータがあります*1

ところが、Traversable は配列ではないので、配列にキャストするときにはオブジェクトとして扱われます。上記のマニュアルに書かれているように、オブジェクトを配列にキャストすると、フィールドの名前と値が key-value として列挙された配列になります。したがって、配列にキャストして null を渡せるようにしたコードは、今度は Traversable を渡せなくなります。私が調べた限りでは、Traversable と通常の配列を統一的に扱う方法は見つかりませんでした。instanceof を使って判断するしかないようです。

結局、array, Traversable, null のどれでも渡せるように書くと、このようなコードになるでしょうか。

<?php
if (!$arr instanceof Traversable) {
    $arr = (array) $array;
}
foreach ($arr as $k => $v) {
    print "$k => $v\n";
}

*1:Traversable を継承した Iterator インタフェースを実装しています。