PHPのiterable
型とTraversable
インターフェイスはどういう性質があるのか?異なる点は何か?どういう関係か?について説明する。
iterable
型
- いわゆる疑似型で、
array
もしくはTraversable
インターフェイスを実装したクラスを指す型。 -
foreach
で反復できる。 -
yield from
のジェネレーター構文が使える。 - PHP7.1で導入された。
Traversable
インターフェイスより新しい。
Traversable
インターフェイス
- このインターフェイスを実装したオブジェクトは
foreach
で反復できるようになる。 - 内部エンジンのインターフェイスであるため、PHPコードでこのインターフェイスを直接実装することはできない特殊なインターフェイスである。
- PHP5で追加された。
class SomeClass implements Traversable {}
//=> Fatal error: Class SomeClass must implement interface Traversable as part of either Iterator or IteratorAggregate
- 実装できないだけで、型宣言で用いたり、他のインターフェイスが
Traversable
インターフェイスを継承することはできる。
interface SomeInterface extends Traversable {} // ok
$obj instanceof Traversable; // ok
function (Traversable $traversable) {} // ok
is_iterable()
関数
- 変数の内容が反復可能な値であることを確認する関数。
is_iterable ( mixed $var ) : bool
-
iterable
疑似型、つまり、array
かTraversable
のときtrue
が返る。
assert(is_iterable([])); // (1) array
assert(is_iterable(new ArrayIterator())); // (2) Traversable
assert(is_iterable((function (): iterable { yield; })())); // (3) Generator
ちなみに(3)はジェネレータ構文を使ったクロージャーを呼び出した結果だが、これはGenerator
クラスとして評価される:
$closure = function (): iterable { yield; };
echo get_class($closure()); //=> Generator
そういえばobject
もforeach
できたよね……?
PHPはオブジェクトもforeach
で反復することができる。
$obj = new stdClass();
$obj->key1 = null;
foreach ($obj as $k => $v) {
echo $k, PHP_EOL; //=> key1
}
しかし、is_iterable
関数ではfalse
になる。
$obj = new stdClass();
$obj->key1 = null;
assert(!is_iterable($obj));
iterable
とTraversable
の関係性
-
Traversable
はiterable
である。 -
array
はiterable
である。 -
array
はTraversable
ではない。 -
Generator
はTraversable
であり、よってiterable
でもある。 -
**Iterator
はTraversable
であり、よってiterable
でもある。 -
Traversable
を実装していないオブジェクトはiterable
ではない。(foreachで回せるが)