Standard PHP Library Iterators

pomosda Slawek Lukasiewicz

I have posted some information about Standard PHP Library recently. Because SPL is one of my favourite PHP extension I decided to write about another neat feature from this toolbox about iterators.

According to wikipedia:
In computer programming, an iterator is an object that enables a programmer to traverse a container. In SPL we can find a lot of implemented Iterators. Most of them are decorators, so they work with other types of iterators.

Examples of SPL iterators

ArrayIterator : with ArrayIterator we can create iterators from array. This is necessary to use with decorators.

<?php
$arrayIterator = new ArrayIterator(array(1, 2, 3));
 
foreach ($arrayIterator as $element) {
	print $element;
	print PHP_EOL;
}
# 1 2 3

Note: in some cases instead of ArrayIterator we can use ArrayObject class, which allows objects work as arrays

RecursiveArrayIterator : ArrayIterator has one drawback. It works only with one dimensional arrays. When we want to use multi dimensional arrays, we should use RecursiveArrayIterator.

To iterate through recursive iterator we can use RecursiveIteratorIterator.

<?php
$recursiveArrayIterator = new RecursiveArrayIterator(
	array('a', array('b', array('c')), array('d'))
);
 
foreach(new RecursiveIteratorIterator($recursiveArrayIterator) as $element)
{
	print $element;
	print PHP_EOL;
}
# a b c d

Note: some other iterators also have Recursive version. You can find them here All of them implement RecursiveIterator interface

Filter Iterator : FilterIterator is responsible for filter unwanted values. It is abstract class with abstract method accept(), which should return true when value is valid, false otherwise.

Filter values greather than 3:

<?php
$arrayIterator = new ArrayIterator(array(2, 4, 6)); 
 
class GreatherThanThreeFilterIterator extends FilterIterator{	
	public function accept()	{		
		return $this->getInnerIterator()->current() > 3;	
	}
}
 
foreach (new GreatherThanThreeFilterIterator($arrayIterator) as $element) {
	print $element;
	print PHP_EOL;
}
# 4 6

Note: to get value for filter we have to invoke $this->getInnerIterator()->current() method.

RegexIterator : Another interesting iterator which can be used for filter values using regular expressions. Print elements that starts with is_ prefix.

<?php
$arrayIterator = new ArrayIterator(array('is_one', 'is_two', 'was_three'));
 
foreach (new RegexIterator($arrayIterator, '/is_*/') as $element) {
	print $element;
	print PHP_EOL;
}
# is_one  is_two

LimitIterator :LimitIterator, as we can guess from name, is responsible for limiting data for iteration. It can be handy when we want to paginate our collection.

<?php
$arrayIterator = new ArrayIterator(array('one', 'two', 'three')); 
 
foreach (new LimitIterator($arrayIterator, 2, 1) as $element) {
	print $element;
	print PHP_EOL;
}
# three

DirectoryIterator : DirectoryIterator provide decent method for getting contents from directory. All files and directories are represented by SplFileInfo object, so all system information can be get for them. Below example of DirectoryIterator usage with FilterIterator to print only files from directory.

<?php
$directoryIterator = new DirectoryIterator('.');
 
class OnlyFilesFilterIterator extends FilterIterator{
 
	public function accept()	{
		return ! $this->getInnerIterator()->current()->isDir();
	}
}
 
foreach(new OnlyFilesFilterrIterator($directoryIterator) as $file) {
	print $file->getFilename();
	print PHP_EOL;
} 

InfiniteIterator : Using InfiniteIterator we can infinitely iterate through collection. So after reaching last element we start iterate from first one automatically. It can be useful for instance when we create some small server or we want to perform some actions before some situation occurs.

<?php

$arrayIterator = new ArrayIterator(array($task1, $task2, $task3));
$infiniteTaskIterator = new InfiniteIterator($arrayIterator);
 
foreach ($infiniteTaskIterator as $task) {
 
	$performSucceded = $task->perform();
	if (false === $performSucceded) {
		break;
	}
	usleep(200);
}

AppendIterator : With AppendIterator we can join more iterators and iterate through them.

<?php

$arrayIterator = new ArrayIterator(array(2, 4, 6));
$arrayIterator2 = new ArrayIterator(array(7, 8, 9)); 
 
$appendIterator = new AppendIterator();
$appendIterator->append($arrayIterator);
$appendIterator->append($arrayIterator2);
 
foreach ($appendIterator as $element) {
	print $element;
	print PHP_EOL;
}
# 2 4 6 7 8 9

GlobIterator : GlobIterator works almost the same as handy glob() function, but return iterator insted of array and elements are SplFileInfo objects. Below code will return all dot files from current directory.

<?php
$globIterator = new GlobIterator('.*');
 
foreach($globIterator as $file) {
	print $file;
	print PHP_EOL;
}

EmptyIterator : On first sight this iterator seems useless. But actually is not. Imagine your method return collection of data, and this collection is used by iterator decorators. But when your collection is empty - what to do ?

We can return false for example, but this will break our decorators chain or create Iterator from empty array. But for more clarity we can return EmptyIterator.

SplFileObject

Using SplFileObject we can iterate through file rows. It is similar to iterating through result of file function

<?php

$fileObject = new SplFileObject('FILE');
 
foreach ($fileObject as $fileRow) {
	print $fileRow.PHP_EOL;
}

Iterator functions

iterator_count : Counting elements inside iterator.

<?php
$arrayIterator = new ArrayIterator(array(1, 2, 3));
print iterator_count($arrayIterator);
# 3

iterator_apply

This function calls a callback function for every element in a iterator.

<?php
$arrayIterator = new ArrayIterator(array(1, 2, 3));
 
function triple(Iterator $iterator) {
    print $iterator->current()*3;
    return true;
}

Note: you can return false to break invoking chain

This is very useful function which creates array from iterator.

<?php
$directoryIterator = new GlobIterator('.*');
var_dump(iterator_to_array($directoryIterator));
# array of SplFileInfo objects
  • 19 Dec 2013
  • By Slawek Lukasiewicz
  • PHP-5
  • 629 Read