【PHP】is_iterable()===falseでもforeachできるオブジェクト

著者:杉浦

【PHP】is_iterable()===falseでもforeachできるオブジェクト

 foreachは繰り返し要素を参照する制御構造です。次図の様に配列の中身を繰り返して扱う時によく使われます。

PHP: foreach – Manual
 is_iterableは変数の内容が反復可能な値であることを確認する関数です。次図の様に与えられた変数の型が配列などの数え上げが可能な型であるか否かを返しています。

PHP: is_iterable – Manual
 is_iterableは反復可能な値であることを確認する関数であり、foreachは繰り返し要素を参照する構文です。であるならば、ある変数$hogeに関してis_iterable($hoge)===falseの時、foreach($hoge as $h)が出来ないように思えます。しかしPHPはちょっと違います。

 is_iterable($hoge)===falseでありながらもforeachが実行されてvar_dumpの出力が表示されています。この現象の理由の一つはオブジェクトの反復処理の定義にあります。公式のマニュアルには次の様にあります。

PHP 5 は、たとえば foreach 命令などによる反復処理を可能とするよう オブジェクトを定義する手段を提供します。 デフォルトで、 全ての アクセス権限がある プロパティは、反復処理に使用することができます。

PHP: オブジェクトの反復処理 – Manual

 これが原因でオブジェクトはis_iterable===falseであってもforeachできます。foreachで参照する要素はアクセス可能なプロパティ全てです。
 foreachできるにもかかわらずis_iterable===falseになる原因はis_iterableが実際にやっている内容が上の画像の端的な説明と異なっている点にあります。実際の挙動においてis_iterableは反復可能な値であるか否かでなく、擬似型iterableを満たすか否かを判定しています。

変数の内容が iterable 疑似型で許容されること、すなわち array、あるいは Traversable を実装したオブジェクトであることを確認する。
PHP: is_iterable – Manual

 まさしく、is iterable?、と訊いているわけですね。
 上記二つの原因によって、iterable型を満たさないオブジェクトは反復処理が可能であるがis_iterable===trueになりません。正直直感的でない仕様であり、少しでもマシにしようとRFCを提出した人もいます。
PHP: rfc:iterable-stdclass

  • この記事いいね! (0)

著者について

杉浦 administrator