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.