permalink

3

Callback Filter Iterator in PHP 5.3/5.4

For anyone who has met me, they would tell you I love the PHP iterators.  I have shared how I feel that are totally under utilized, http://speakerdeck.com/u/jakefolio/p/unsung-heroes-of-php.  The biggest down fall to Iterators in PHP is the documentation.  The documentation is very limited and it’s not always clear when is a good time to use an iterator.

Back in June of this year, I was looking at the documentation on http://www.php.net/manual/en/spl.iterators.php and I found there was a new iterator, YAY! This Iterator is built for PHP 5.4+, but obviously I can’t/don’t want to run PHP 5.4 in  production yet.  I liked the concept of the iterator so much I decided to create it to be used in PHP 5.3+

The Filter Iterator is probably my second favorite iterator, next to Directory Iterator.  There are many great use cases for the Filter Iterator, and when you do filter the original data is left untouched. A Filter Iterator is really simple to use, create a class that extends FilterIterator and adjust the accept method to meet your criteria.  This is great and all, but having the ability to create filter iterators on the fly, ones that won’t be used application wide, without having to create a class is even better.

Let’s get to the code already!

class FilterCallbackIterator extends FilterIterator {
  protected $callback;
 
  public function __construct(Iterator $it, Closure $callback = null)
  {
    $this->callback = $callback;
    parent::__construct($it);
  }
 
  public function accept()
  {
    return call_user_func($this->callback, $this->current(), $this->key(), $this->getInnerIterator());
  }
 
  public function callback($callback) {
    $this->callback = $callback;
    return $this;
  }
 
}

As you can see I extended the FilterIterator like you normally would.  Then my construct requires an Inner Iterator to be passed in (this can be a directory iterator, array iterator, etc.) and also the callback (anonymous function or closure). I store the callback for later use and run the parent construct to add the Inner Iterator.

As I mentioned earlier the accept method is the only method you have to change to make the Filter Iterator fit your criteria.  It is very simple, return true or false.  I use call_user_func because I’m storing the callback in an object property and that is the simplest way to run it.  I pass the parameters current, key and inner iterator to the callback.  I do this because this is how the class will work in PHP 5.4.

I’m sure you’re wondering why I have callback method also, and why does it return the object?  I wanted to be able to change the criteria of acceptance whenever I wanted, you may notice the callback isn’t required in the construct.

Let’s test this code:

$data = array(2, 5, 20, 23432, 120, 12, 3);
 
$it = new ArrayIterator($data);
 
$filterCB = new FilterCallbackIterator($it);
 
$gt10 = $filterCB->callback(function($val) {
  if ($val > 10) { return true; }
  return false;
});
 
echo "Greater than 10\n";
foreach($gt10 as $result) {
  echo $result . "\n";
}

My example is very simple.  I want to output only values that are greater than 10.  I pass in my anonymous function to do this test for me.  And the output should look like this:

Greater than 10
20
23432
120
12

That was fun, but lets show only those greater than 100 later in our script:

$gt100 = $filterCB->callback(function($val) {
  if ($val > 100) { return true; }
  return false;
});
 
echo "Greater than 100\n";
foreach($gt100 as $result) {
  echo $result . "\n";
}

As you can see, all I had to do was update my callback and it is now testing my new criteria. The result with both the examples would be:

Greater than 10
20
23432
120
12
Greater than 100
23432
120

The Possibilities are endless with the CallbackFilterIterator. This blog post was a simple introduction to what you can do. * Note: I named my class differently from the actual class being used in PHP 5.4 to avoid any conflicts. *

To the view the docs for the upcomaing CallbackFilterIterator: http://www.php.net/manual/en/class.callbackfilteriterator.php

  • http://www.scripting4you.com/blog/2011/12/jake-smiths-blog-callback-filter-iterator-in-php-5-35-4/ Jake Smith’s Blog: Callback Filter Iterator in PHP 5.3/5.4 | Scripting4You Blog

    [...] blog today about a feature included in PHP's Standard PHP Library that you might have overlooked – the FilterIterator's callback functionality. The Filter Iterator is probably my second favorite iterator, next to Directory Iterator. There [...]

  • http://www.syngu.com/development/2998655698/callback-filter-iterator-in-php-5.3-5.4/ Callback Filter Iterator in PHP 5.3/5.4 | PHP | Syngu

    [...] For anyone who has met me, they would tell you I love the PHP iterators.  I have shared how I feel that are totally under utilized, http://speakerdeck.com/u/jakefolio/p/unsung-heroes-of-php.  The biggest down fall to Iterators in PHP is the documentation.  The documentation is very limited and it’s not always clear when is a good time to use an iterator.    PHP Read the original post on DZone… [...]

  • http://www.developercast.com/2011/12/02/jake-smiths-blog-callback-filter-iterator-in-php-5-35-4/ Development Blog With Code Updates : Developercast.com » Jake Smith’s Blog: Callback Filter Iterator in PHP 5.3/5.4 » Development Blog With Code Updates : Developercast.com

    [...] about a feature included in PHP’s Standard PHP Library that you might have overlooked – the FilterIterator’s callback functionality. The Filter Iterator is probably my second favorite iterator, next to Directory Iterator. There [...]