最可靠的方法是使用 is_iterable() 函数(PHP 7.1+),它统一覆盖数组、Traversable 对象和生成器;若需兼容旧版本,则用 instanceof Traversable 结合 is_array()。

用 instanceof 判断是否为迭代器(最可靠)
PHP 中判断一个变量是否为迭代器,核心是看它是否实现了 Iterator 或 Traversable 接口。直接用 instanceof Iterator 可能漏掉某些对象(比如只实现 Traversable 的生成器委托类),所以应优先检测 Traversable —— 它是所有可迭代结构的底层接口。
-
Traversable是抽象接口,无法被implements,只能被Iterator或IteratorAggregate间接实现,但instanceof Traversable仍可安全使用 - 生成器(
Generator)、ArrayIterator、DirectoryIterator、自定义IteratorAggregate类都返回true - 普通数组、
stdClass、字符串、null都返回false
示例:
立即学习“PHP免费学习笔记(深入)”;
$it = new ArrayIterator([1, 2, 3]);
var_dump($it instanceof Traversable); // true
$gen = (function() { yield 1; })();
var_dump($gen instanceof Traversable); // true
$arr = [1, 2, 3];
var_dump($arr instanceof Traversable); // false
is_iterable() 函数:PHP 7.1+ 的快捷方式
is_iterable() 是 PHP 内置函数,语义明确且覆盖全面:它对数组、Traversable 对象、生成器都返回 true,比手写 instanceof 更省心。
- 注意:它对
string返回false(即使字符串可被foreach遍历,但 PHP 不认为它是“iterable”类型) - 对
Resource、bool、int等标量一律false - 兼容性要求 PHP ≥ 7.1;若项目需支持更低版本,必须回退到
instanceof Traversable+is_array()组合判断
示例:
立即学习“PHP免费学习笔记(深入)”;
var_dump(is_iterable([1,2])); // true
var_dump(is_iterable(new ArrayIterator([]))); // true
var_dump(is_iterable("hello")); // false
var_dump(is_iterable(null)); // false
别用 is_object() + method_exists() 检查 current()
有人会尝试通过检查对象是否有 current()、next() 等方法来“模拟”迭代器判断,这是危险的误判路径。
- 很多非迭代器类也可能有同名方法(比如模型类加了
current()用于返回当前状态) - 缺少接口约束,无法保证方法行为符合迭代协议
-
IteratorAggregate类本身不实现current(),而是靠getIterator()返回真实迭代器,这种检测会直接失败
结论:绕过接口契约去“猜”行为,既不可靠又难维护,应彻底避免。
实际使用中容易忽略的边界情况
真正上线时,几个点常被跳过但影响逻辑健壮性:
- 生成器一旦被遍历过一次,再次
foreach会静默不执行——检测出是Traversable后,若需多次消费,得确认它是否可重用(比如包装成CallbackFilterIterator或缓存结果) -
IteratorAggregate实现类若在getIterator()中返回null或非Traversable,foreach会报Fatal error,但instanceof Traversable仍为true(因为对象本身是Traversable子类) - 扩展类如
SplFixedArray不实现Traversable,但它支持foreach;此时is_iterable()返回true,而instanceof Traversable为false—— 所以优先用is_iterable(),除非你明确只要标准迭代器协议
接口判断这事,看着简单,但生成器生命周期、聚合迭代器的惰性求值、以及 SPL 类的特殊实现,都会让“能 foreach”和“是迭代器”产生微妙偏差。










