Overview
The iterable pseudo-type was introduced in PHP 7.1. It’s a valuable feature for developers that allows functions to accept both arrays and objects as input, provided that the objects are instances of Traversable, which means they can be iterated over. Understanding how to effectively use iterable helps create more flexible and robust code.
Understanding iterable
In PHP, iterable is a pseudo-type that can accept any array or object implementing the Traversable interface. Before PHP 7.1, you had to hint either array or Traversable, but iterable allows a function to accept both, providing greater flexibility.
function printValues(iterable $items) {
foreach ($items as $item) {
echo $item;
}
}
printValues([1, 2, 3]); // Outputs: 123
printValues(new ArrayIterator([1, 2, 3])); // Outputs: 123
Iterating over an iterable
Using iterable, we can write a function that accepts any traversable data structure and performs an iteration.
// Define a function that uses iterable
function processIterable(iterable $data) {
foreach ($data as $value) {
// Process each element.
}
}
// Use an array
processIterable([1, 2, 3, 4, 5]);
// Or use an Iterator
processIterable(new ArrayIterator([1, 2, 3, 4, 5]));
Type checking iterable
It’s also possible to verify if a variable is an iterable using the is_iterable() function. This helps in ensuring that the provided data conforms to expected types before performing operations.
$array = [1, 2, 3];
$notIterable = 123;
if (is_iterable($array)) {
// It is iterable
}
if (!is_iterable($notIterable)) {
// This is not iterable and will throw a TypeError if used in an iteration context.
}
Creating a custom iterable class
To create a custom object that is iterable, you typically implement the Iterator or IteratorAggregate interface. Here’s an example of implementing Iterator.
class MyIterableClass implements Iterator {
private $items = [];
private $index = 0;
public function __construct($items) {
$this->items = array_values($items);
}
public function current() {
return $this->items[$this->index];
}
public function key() {
return $this->index;
}
public function next() {
++$this->index;
}
public function rewind() {
$this->index = 0;
}
public function valid() {
return isset($this->items[$this->index]);
}
}
$myIterable = new MyIterableClass(["a", "b", "c"]);
foreach ($myIterable as $item) {
echo $item; // Outputs: abc
}
Iterable and Generators
Generators provide an easy way to implement simple iterators. Using yield, we can create a function that generates an iterable sequence of values without implementing any interfaces.
function generator(): iterable {
yield 'a';
yield 'b';
yield 'c';
}
foreach (generator() as $value) {
echo $value; // Outputs: abc
}
Combining iterable with other types
As of PHP 8.0, it is possible to combine iterable with another type in a union type declaration. This enhancement increases the flexibility of function parameter types even further.
function combineTypes(iterable|string $data) {
if (is_iterable($data)) {
foreach ($data as $item) {
echo $item;
}
} else {
echo $data;
}
}
combineTypes(["a", "b", "c"]); // Outputs: abc
combineTypes("abc"); // Outputs: abc
Conclusion
The introduction of iterable in PHP has enabled developers to create more flexible functions and methods, especially when dealing with collections of data. By understanding and using iterable, PHP developers can write clearer and more maintainable code. It’s a feature that showcases PHP’s constant evolution towards a more robust and versatile language.