Signature
is_iterable(mixed $value): boolPurpose
is_iterable() answers one question: could this value be accepted by the iterable pseudo-type? In practice that means the value is either an array or an object that implements Traversable. It is a runtime check you can use before looping over input whose type you do not control, such as a function argument declared mixed, a decoded configuration value, or data handed over by a plugin.
Signature
Parameters and defaults
$value: any value. There are no other parameters and no defaults. Because the type ismixed, you can pass integers, strings,null, arrays, objects or anything else without causing a type error.
Return value and failure cases
The function returns true when the value is an array or a Traversable object, and false for everything else. It never throws for ordinary values and does not emit warnings. The result is a plain boolean, so it works directly inside if conditions.
The check does not look inside the value. An empty array is iterable. A generator is iterable. The function does not advance, rewind or consume anything, so calling it on a generator leaves the generator untouched.
Example 1: Scalars, null, arrays and plain objects
This example runs several kinds of value through the function and prints the results as JSON.
$values = [
'array' => [1, 2, 3],
'empty array' => [],
'string' => 'abc',
'int' => 1,
'null' => null,
'stdClass' => new stdClass(),
];
$result = [];
foreach ($values as $label => $value) {
$result[$label] = is_iterable($value);
}
echo json_encode($result, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";{"array":true,"empty array":true,"string":false,"int":false,"null":false,"stdClass":false}
Notice that a string is not iterable even though you can read its characters by offset, and that a plain stdClass object is not iterable even though foreach can walk its public properties.
Example 2: Traversable objects
Any class that implements Iterator or IteratorAggregate is Traversable, and so is every generator. A class that implements only some other interface, such as Countable, does not qualify.
function makeGenerator(): Generator {
yield 1;
yield 2;
}
class Box implements Countable {
public function count(): int { return 0; }
}
$result = [
'ArrayIterator' => is_iterable(new ArrayIterator([1, 2])),
'ArrayObject' => is_iterable(new ArrayObject([1, 2])),
'Generator' => is_iterable(makeGenerator()),
'Box' => is_iterable(new Box()),
];
echo json_encode($result, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";{"ArrayIterator":true,"ArrayObject":true,"Generator":true,"Box":false}
Example 3: Guarding a loop
A common use is validating input at the top of a function that accepts several shapes of collection.
function sumItems(mixed $items): int {
if (!is_iterable($items)) {
throw new InvalidArgumentException('Expected an iterable value.');
}
$total = 0;
foreach ($items as $item) {
$total += $item;
}
return $total;
}
function numbers(): Generator {
yield 4;
yield 5;
}
echo sumItems([1, 2, 3]), "\n";
echo sumItems(numbers()), "\n";
try {
sumItems(10);
} catch (InvalidArgumentException $e) {
echo $e->getMessage(), "\n";
}6 9 Expected an iterable value.
If the parameter could simply be declared iterable, PHP would reject bad values for you with a TypeError. The explicit check is useful when you want a custom exception, a fallback, or when the parameter has to stay mixed.
Edge cases
- Empty arrays are iterable. The check is about type, not content.
- Generators are
Traversable, so they pass. Iterating one consumes it, butis_iterable()itself does not. - Objects with public properties are not iterable unless their class implements
Traversable, even thoughforeachaccepts them. - Strings are never iterable. Use
str_split()or index access if you need characters. nullreturnsfalse, so an optional collection argument needs a separatenullcheck or a default.
Common mistakes
- Assuming
is_iterable()means countable. A generator is iterable but cannot be counted withcount(). Useis_countable()for that question. - Using
is_array()when objects should also be accepted.is_array()rejectsArrayIterator,ArrayObjectand generators. - Treating a
trueresult as permission to index the value with$items[0]. Only arrays andArrayAccessobjects support that. - Looping twice over a value that passed the check. A generator cannot be rewound after it has advanced, so the second pass fails.
- Expecting plain objects to pass because
foreachcan read their properties.
Related functions
is_array()checks only for arrays.is_countable()checks for arrays orCountableobjects.is_object()checks for any object.iterator_to_array()converts aTraversableinto an array, and works only after you know you have aTraversable.
Recap
is_iterable() takes one mixed value and returns true for arrays and Traversable objects, false otherwise. It is safe to call on any value, does not consume generators, and is the right guard when a function must accept both arrays and iterator-like objects.
Tested examples
$values = [
'array' => [1, 2, 3],
'empty array' => [],
'string' => 'abc',
'int' => 1,
'null' => null,
'stdClass' => new stdClass(),
];
$result = [];
foreach ($values as $label => $value) {
$result[$label] = is_iterable($value);
}
echo json_encode($result, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";{"array":true,"empty array":true,"string":false,"int":false,"null":false,"stdClass":false}
function makeGenerator(): Generator {
yield 1;
yield 2;
}
class Box implements Countable {
public function count(): int { return 0; }
}
$result = [
'ArrayIterator' => is_iterable(new ArrayIterator([1, 2])),
'ArrayObject' => is_iterable(new ArrayObject([1, 2])),
'Generator' => is_iterable(makeGenerator()),
'Box' => is_iterable(new Box()),
];
echo json_encode($result, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), "\n";{"ArrayIterator":true,"ArrayObject":true,"Generator":true,"Box":false}
function sumItems(mixed $items): int {
if (!is_iterable($items)) {
throw new InvalidArgumentException('Expected an iterable value.');
}
$total = 0;
foreach ($items as $item) {
$total += $item;
}
return $total;
}
function numbers(): Generator {
yield 4;
yield 5;
}
echo sumItems([1, 2, 3]), "\n";
echo sumItems(numbers()), "\n";
try {
sumItems(10);
} catch (InvalidArgumentException $e) {
echo $e->getMessage(), "\n";
}6 9 Expected an iterable value.