classObj1{public$v='V:Obj1';private$prv='prv:Obj1';}$obj1=newObj1();echo$obj1instanceofTraversable?'yes':'no',PHP_EOL;//noclassObj2implementsIteratorAggregate{public$v='V:Obj2';private$prv='prv:Obj2';publicfunctiongetIterator(){returnnewArrayIterator(['v'=>$this->v,'prv'=>$this->prv,]);}}$obj2=newObj2();echo$obj2instanceofTraversable?'yes':'no',PHP_EOL;//yes
从上面的例子中可以看出,每一个 $obj1 无法通过 Traversable 判断,以是它是不能被遍历的。而第二个 $obj2 则是实现了迭代器接口,这个工具是可以通过 Traversable 判断的。在PHP手册中,Traversable 接口正是用于检测一个类是否可以被 foreach 遍历的接口。
这个接口有几个特点:
也便是说这个接口不须要我们去手工实现,只须要我们的类实现迭代器干系的接口就可以通过这个接口的验证的判断。如果单独去实现这个接口的话,将会报错并提示我们该当去实现 IteratorAggregate 或 Iterator 接口。

//Fatalerror:ClassImplTraversablemustimplementinterfaceTraversableaspartofeitherIteratororIteratorAggregateinUnknownclassImplTraversableimplementsTraversable{}
实在之前的文章中,我们已履历证过,工具是可以被遍历的,而且并不须要实现什么迭代器接口就可以被 foreach 遍历。它会输出 所有 public 的属性。
//foreachforeach($obj1as$o1){echo$o1,PHP_EOL;}foreach($obj2as$o2){echo$o2,PHP_EOL;}//V:Obj1//V:Obj2//prv:Obj2
也便是说这个 Traversable 接口的浸染在实际利用中并不明显。相信我们决大部分人也并没有利用过这个接口来判断过类是否可以被遍历。但是从上面的例子中我们可以看出,迭代器能够自定义我们须要输出的内容。相对来说比直接的工具遍历更加的灵巧可控。其余,如果是数组强转工具的情形,Traversable 接口同样无法进行判断。
$arr=[1,2,3,4];$obj3=(object)$arr;echo$obj3instanceofTraversable?'yes':'no',PHP_EOL;//noforeach($obj3as$o3){echo$o3,PHP_EOL;}
实在,数组本身便是天然的可迭代工具。这里虽然进行了类型强转,但实在该当将数组强转的工具视为默认实现了迭代的器的工具更得当。当然,这类接口更大的意义还是在于代码规范及逼迫检讨方面。
测试代码: https://github.com/zhangyue0503/dev-blog/blob/master/php/202003/source/%E5%9C%A8PHP%E4%B8%AD%E6%A3%80%E6%B5%8B%E4%B8%80%E4%B8%AA%E7%B1%BB%E6%98%AF%E5%90%A6%E5%8F%AF%E4%BB%A5%E8%A2%ABforeach%E9%81%8D%E5%8E%86.php
参考文档: https://www.php.net/manual/zh/class.traversable.php https://www.php.net/manual/zh/control-structures.foreach.php https://www.php.net/manual/zh/language.oop5.iterations.php