PHP is_iterable() 函数(快速上手)

PHP is_iterable() 函数:判断数据是否可迭代的实用工具

在 PHP 开发中,我们经常需要处理数组、对象等数据结构,尤其是在编写函数时,希望函数能同时支持多种数据类型。例如,一个函数可能需要遍历传入的参数,但这个参数可能是数组,也可能是实现了 Traversable 接口的对象。这时候,传统的 is_array() 函数就显得力不从心了,因为它无法识别 IteratorGenerator 类型。

为了解决这个问题,PHP 7.1 引入了一个非常实用的函数:is_iterable()。它能准确判断一个变量是否可以被 foreach 遍历,是处理泛型数据输入时的利器。


什么是“可迭代”?—— 从生活中的例子说起

想象你有一本字典。你能从头到尾一页一页翻,也可以直接跳到某个词查找。这种“能被逐个访问”的特性,就是“可迭代”的本质。

在编程中,任何能被 foreach 循环使用的数据结构,都可以称为“可迭代”的。这包括:

  • 数组(Array)
  • 实现了 Traversable 接口的对象(如 ArrayObject
  • 生成器(Generator)
  • 以及任何通过 Iterator 接口实现的类

换句话说,只要一个变量能用 foreach ($data as $item) 的方式遍历,它就是可迭代的。

is_iterable() 函数,就是用来判断这一点的。


基础用法:如何使用 PHP is_iterable() 函数

is_iterable() 是一个内置函数,返回布尔值:true 表示可迭代,false 表示不可迭代。

<?php

// 示例 1:数组是可迭代的
$myArray = [1, 2, 3, 4];
var_dump(is_iterable($myArray)); // 输出:bool(true)

// 示例 2:普通字符串不是可迭代的
$myString = "hello";
var_dump(is_iterable($myString)); // 输出:bool(false)

// 示例 3:空数组也是可迭代的
$emptyArray = [];
var_dump(is_iterable($emptyArray)); // 输出:bool(true)

// 示例 4:对象如果实现了 Traversable 接口,就是可迭代的
class MyIterator implements Traversable {
    private $data = [1, 2, 3];

    public function getIterator() {
        return new ArrayIterator($this->data);
    }
}

$obj = new MyIterator();
var_dump(is_iterable($obj)); // 输出:bool(true)

?>

注意is_iterable() 不会检查数据是否为空,它只关心“是否支持遍历”。所以空数组、空对象、空生成器,只要结构合法,都会返回 true


与 is_array() 的对比:你真的需要它吗?

很多初学者习惯用 is_array() 来判断是否能遍历。但这是个误区。

<?php

$generator = (function () {
    yield 1;
    yield 2;
    yield 3;
})();

// is_array() 无法识别生成器
var_dump(is_array($generator)); // bool(false)

// is_iterable() 可以识别生成器
var_dump(is_iterable($generator)); // bool(true)

?>

从上面的例子可以看出,is_array() 仅限于判断是否为数组类型,而 is_iterable() 更加通用,能覆盖所有可遍历的数据类型。

建议:当你需要处理“可能为数组、也可能为对象或生成器”的输入时,优先使用 is_iterable(),避免类型判断遗漏。


实际应用场景:编写灵活的工具函数

我们来做一个实用的函数,它能接收任意可迭代的数据,并输出每一项的内容。

<?php

/**
 * 输出可迭代数据中的每一项
 * 支持数组、对象、生成器等
 *
 * @param mixed $data 要输出的数据
 */
function printIterable($data) {
    // 使用 is_iterable 检查输入是否可遍历
    if (!is_iterable($data)) {
        echo "错误:输入的数据不可迭代。\n";
        return;
    }

    echo "开始输出数据:\n";
    foreach ($data as $key => $value) {
        echo "键:$key,值:$value\n";
    }
    echo "输出完成。\n";
}

// 测试用例 1:数组
printIterable([10, 20, 30]);

// 测试用例 2:生成器
$gen = (function () {
    for ($i = 1; $i <= 3; $i++) {
        yield "item_$i";
    }
});
printIterable($gen);

// 测试用例 3:自定义对象
class DataContainer implements Traversable {
    private $items = ['a', 'b', 'c'];

    public function getIterator() {
        return new ArrayIterator($this->items);
    }
}

$obj = new DataContainer();
printIterable($obj);

// 测试用例 4:不可迭代的字符串
printIterable("hello");

?>

输出结果

开始输出数据:
键:0,值:10
键:1,值:20
键:2,值:30
输出完成。
开始输出数据:
键:0,值:item_1
键:1,值:item_2
键:2,值:item_3
输出完成。
开始输出数据:
键:0,值:a
键:1,值:b
键:2,值:c
输出完成。
错误:输入的数据不可迭代。

这个例子展示了 is_iterable() 如何让函数变得更健壮和通用。你不需要为每种类型写不同的逻辑,只需一次判断即可处理所有情况。


常见误区与注意事项

误区 1:认为 is_iterable() 只判断数组

很多人误以为 is_iterable() 只能判断数组,其实它能识别的类型远超数组。

类型 是否可迭代 说明
数组 ✅ 是 最常见类型
生成器 ✅ 是 通过 yield 返回数据
ArrayObject ✅ 是 实现了 Traversable
Iterator 对象 ✅ 是 ArrayIterator
普通对象 ❌ 否 除非实现 Traversable
字符串 ❌ 否 即使是字符数组也不行
数字 ❌ 否 如 123、3.14

重要提醒:字符串虽然可以被 for 循环遍历字符,但 不能foreach 遍历,因此 is_iterable() 返回 false

误区 2:误以为可迭代的变量一定有键值

在数组中,foreach 会返回键和值。但在生成器或某些对象中,键可能是自动递增的,或为 null

<?php

$gen = (function () {
    yield "apple";
    yield "banana";
    yield "cherry";
})();

foreach ($gen as $key => $value) {
    echo "键:$key,值:$value\n";
}
// 输出:
// 键:0,值:apple
// 键:1,值:banana
// 键:2,值:cherry
?>

即使没有显式定义键,is_iterable() 也允许遍历,但键由 PHP 自动分配。


性能与最佳实践建议

is_iterable() 是一个轻量级的内置函数,性能极高。它内部通过类型检查和接口判断实现,不会产生额外开销。

✅ 推荐做法:

  • 在函数参数类型不确定时,使用 is_iterable() 做前置校验
  • 避免在循环中重复调用,只在入口处判断一次
  • 结合类型声明(如 iterable)使用,增强代码可读性
<?php

// 推荐:结合类型声明使用
function processItems(iterable $items): void {
    foreach ($items as $item) {
        echo "处理:$item\n";
    }
}

// 调用时,传入数组、生成器都合法
processItems([1, 2, 3]);
processItems((function () { yield 1; yield 2; })());
?>

注:iterable 是 PHP 7.1 引入的类型声明,与 is_iterable() 相辅相成,一个用于函数签名,一个用于运行时判断。


总结:为什么你该用 PHP is_iterable() 函数

is_iterable() 函数虽然简单,却在实际开发中作用巨大。它解决了类型判断的“盲区”,让代码更健壮、更灵活。

  • 它能识别数组、生成器、Traversable 对象
  • is_array() 相比,覆盖面更广
  • 是编写通用工具函数的“黄金标准”
  • 无需额外依赖,性能优异

无论你是初学者还是中级开发者,掌握这个函数,都能让你写出更优雅、更安全的 PHP 代码。

下次当你需要“判断一个变量能不能被 foreach 遍历”时,别再用 is_array() 了,试试 is_iterable(),它会让你少走很多弯路。