আগামী ১৫ ডিসেম্বর -২০১৭ তারিখ থেকে শুরু হচ্ছে পাঁচ মাস ব্যাপী Professional Web Design and Development with HTML, CSS PHP,MySQL,JavaScript, AJAX, JQUERY, Bootstrap and Live Project কোর্সের ৮৭ তম ব্যাচ এবং ২৬ ডিসেম্বর-২০১৭ তারিখ থেকে শুরু হচ্ছে চার মাস ব্যাপী Zend PHP-7 Certified PHP Engineering (Advance PHP) কোর্সের ৩৫ তম ব্যাচ। প্রত্যেকটি কোর্স এর ফী নির্ধারণ করা হয়েছে ৩০,০০০/= আগ্রহীদেরকে অতিসত্বর মাসুদ আলম স্যার এর সাথে যোগাযোগ করতে অনুরোধ করা যাচ্ছে। স্যার এর মোবাইল: 01722 81 75 91

Introduction to Standard PHP Library-SPL Part-1

Introduction to Standard PHP Library-SPL Part-1

Today I’ll look at some iterators: a set of classes in the SPL that implements various iterating patterns: ArrayIterator, AppendIterator,FilterIterator. Hopefully you’ll get a idea of what these are capable of and that you can get some new ideas for your day-to-day tasks.

What is SPL.

SPL provides a standard set of interfaces for PHP5. The aim of SPL is to implement some efficient data access interfaces and classes for PHP. Functionally it is designed to traverse aggregate structures (anything you want to loop over). These may include arrays, database result sets, xml trees, directory listings or any list at all. Currently SPL deals with Iterator. To see all the classes available to SPL, this simple snippet will show you.

</p>
<?php
 // a simple foreach() to traverse the SPL class names
 foreach(spl_classes() as $key=>$value)
 {
 echo $key.' -> '.$value.'<br />';
 }
 ?>

This will provide you with a list something like this:

  • AppendIterator -> AppendIterator
  • ArrayIterator -> ArrayIterator
  • ArrayObject -> ArrayObject
  • BadFunctionCallException -> BadFunctionCallException
  • BadMethodCallException -> BadMethodCallException
  • CachingIterator -> CachingIterator
  • Countable -> Countable
  • DirectoryIterator -> DirectoryIterator
  • DomainException -> DomainException
  • EmptyIterator -> EmptyIterator
  • FilterIterator -> FilterIterator
  • InfiniteIterator -> InfiniteIterator
  • InvalidArgumentException -> InvalidArgumentException
  • IteratorIterator -> IteratorIterator
  • LengthException -> LengthException
  • LimitIterator -> LimitIterator
  • LogicException -> LogicException
  • NoRewindIterator -> NoRewindIterator
  • OuterIterator -> OuterIterator
  • OutOfBoundsException -> OutOfBoundsException
  • OutOfRangeException -> OutOfRangeException
  • OverflowException -> OverflowException
  • ParentIterator -> ParentIterator
  • RangeException -> RangeException
  • RecursiveArrayIterator -> RecursiveArrayIterator
  • RecursiveCachingIterator -> RecursiveCachingIterator
  • RecursiveDirectoryIterator -> RecursiveDirectoryIterator
  • RecursiveFilterIterator -> RecursiveFilterIterator
  • RecursiveIterator -> RecursiveIterator
  • RecursiveIteratorIterator -> RecursiveIteratorIterator
  • RecursiveRegexIterator -> RecursiveRegexIterator
  • RegexIterator -> RegexIterator
  • RuntimeException -> RuntimeException
  • SeekableIterator -> SeekableIterator
  • SimpleXMLIterator -> SimpleXMLIterator
  • SplFileInfo -> SplFileInfo
  • SplFileObject -> SplFileObject
  • SplObjectStorage -> SplObjectStorage
  • SplObserver -> SplObserver
  • SplSubject -> SplSubject
  • SplTempFileObject -> SplTempFileObject
  • UnderflowException -> UnderflowException
  • UnexpectedValueException -> UnexpectedValueException

What are iterators?

An Iterator is an object that traverses a structure eg: an array or a directory listing or possibly a set of database result sets or other resource. This is not an accurate description, but more will become clear later by way of example. There are different types of Iterators for dealing with different types of data such as array Iterators, Directory Iterators and more. Here we will begin to get familiar with them beginning with the DirectoryIterator. What is important to note is they can all be accessed with a standard interface. This means that regardless of the data type, access to the information is standardized. This is a real step forward for PHP.

ArrayIterator

The ArrayIterator does exactly what it tells you: it’s used to iterate over an array of values, with it you can easily iterate over values like you would any other collection with a normal iterator. It has the ability to seek and rewind on the array in question and get the current key and value.

ArrayIterator::current

ArrayIterator::current — Return current array entry

Example #1 ArrayIterator::current() example

File: array_iterator_current.php

<?php
 $array = array('1' => 'one',
                '2' => 'two',
                '3' => 'three');

 $arrayobject = new ArrayObject($array);

 for($iterator = $arrayobject->getIterator();
     $iterator->valid();
     $iterator->next()) {

     echo $iterator->key() . ' => ' . $iterator->current() . "\n";
 }
 ?>

The above example will output:

1 => one

2 => two

3 => three

ArrayIterator::next

ArrayIterator::next — Move to next entry

Example #1 ArrayIterator::next() example

File: array_iterator_next.php

<?php
 $arrayobject = new ArrayObject();

 $arrayobject[] = 'zero';
 $arrayobject[] = 'one';

 $iterator = $arrayobject->getIterator();

 while($iterator->valid()) {
     echo $iterator->key() . ' => ' . $iterator->current() . "\n";

     $iterator->next();
 }
 ?>

The above example will output:
0 => zero
1 => one

ArrayIterator::rewind — Rewind array back to the start

Example #1 ArrayIterator::rewind() example

File: array_iterator_rewind.php

<?php

$arrayobject = new ArrayObject();

$arrayobject[] = 'zero';

$arrayobject[] = 'one';

$arrayobject[] = 'two';

$iterator = $arrayobject->getIterator();

$iterator->next();

echo $iterator->key(); //1

$iterator->rewind(); //rewinding to the begining

echo $iterator->key(); //0

?>

ArrayIterator::valid

ArrayIterator::valid — Check whether array contains more entries

Example #1 ArrayIterator::valid() example

File: array_iterator_valid.php

<?php
 $array = array('1' => 'one');

 $arrayobject = new ArrayObject($array);
 $iterator = $arrayobject->getIterator();

 var_dump($iterator->valid()); //bool(true)

 $iterator->next(); // advance to the next item

 //bool(false) because there is only one array element
 var_dump($iterator->valid());
 ?>

AppendIterator

In the example above we looked at how we can iterate over a single ArrayObject and how the IteratorAggregate interface works, but: if you have multiple elements you might want to iterate over all of these together, this is where the AppendIterator comes to help you.

The following example creates two ArrayObjects and a AppendIterator, there is only a single method here that you need to think about, the append() function that takes a Iterator as argument. The point of the iterator is to collect several collections and iterate over them in one go:

AppendIterator::append

AppendIterator::append — Appends an iterator

Example #1 AppendIterator::append() example

File: append_iterator_append.php

<?php
 $array_a = new ArrayIterator(array('a', 'b', 'c'));
 $array_b = new ArrayIterator(array('d', 'e', 'f'));

 $iterator = new AppendIterator;
 $iterator->append($array_a);
 $iterator->append($array_b);

 foreach ($iterator as $current) {
     echo $current;
 }
 ?>

The above example will output:

Abcdef
AppendIterator::__construct

AppendIterator::__construct — Constructs an AppendIterator

Example #1 Iterating AppendIterator with foreach

File: Iterating_AppendIterator_with_foreach.php

<?php
 $pizzas   = new ArrayIterator(array('Margarita', 'Siciliana', 'Hawaii'));
 $toppings = new ArrayIterator(array('Cheese', 'Anchovies', 'Olives', 'Pineapple', 'Ham'));

 $appendIterator = new AppendIterator;
 $appendIterator->append($pizzas);
 $appendIterator->append($toppings);

 foreach ($appendIterator as $key => $item) {
     echo $key . ' => ' . $item . PHP_EOL;
 }
 ?>

The above example will output:

0 => Margarita
1 => Siciliana
2 => Hawaii
0 => Cheese
1 => Anchovies
2 => Olives
3 => Pineapple
4 => Ham
Example #2 Iterating AppendIterator with the AppendIterator API

File: Iterating_AppendIterator_with_the_AppendIterator_API.php

<?php
 $pizzas   = new ArrayIterator(array('Margarita', 'Siciliana', 'Hawaii'));
 $toppings = new ArrayIterator(array('Cheese', 'Anchovies', 'Olives', 'Pineapple', 'Ham'));

 $appendIterator = new AppendIterator;
 $appendIterator->append($pizzas);
 $appendIterator->append($toppings);

 while ($appendIterator->valid()) {
     printf(
         '%s => %s => %s%s',
         $appendIterator->getIteratorIndex(),
         $appendIterator->key(),
         $appendIterator->current(),
         PHP_EOL
     );
     $appendIterator->next();
 }
 ?>

The above example will output:

0 => 0 => Margarita
0 => 1 => Siciliana
0 => 2 => Hawaii
1 => 0 => Cheese
1 => 1 => Anchovies
1 => 2 => Olives
1 => 3 => Pineapple
1 => 4 => Ham
AppendIterator::getInnerIterator

This method returns the current inner iterator.

Example #1 AppendIterator::getInnerIterator() example

File: append_iterator_get_inner_iterator.php

<?php
 $array_a = new ArrayIterator(array('a' => 'aardwolf', 'b' => 'bear', 'c' => 'capybara'));
 $array_b = new RegexIterator($array_a, '/^[ac]/');

 $iterator = new AppendIterator;
 $iterator->append($array_a);
 $iterator->append($array_b);

 foreach ($iterator as $current) {
     $inner = $iterator->getInnerIterator();
     if ($inner instanceOf RegexIterator) {
         echo 'Filtered: ';
     } else {
         echo 'Original: ';
     }
     echo $current . PHP_EOL;
 }
 ?>

The above example will output:

Original: aardwolf
Original: bear
Original: capybara
Filtered: aardwolf
Filtered: capybara
AppendIterator::getIteratorIndex

AppendIterator::getIteratorIndex — Gets an index of iterators

Example #1 AppendIterator.getIteratorIndex() basic example

File: AppendIterator.getIteratorIndex.php

<?php
 $array_a = new ArrayIterator(array('a' => 'aardwolf', 'b' => 'bear', 'c' => 'capybara'));
 $array_b = new ArrayIterator(array('apple', 'orange', 'lemon'));

 $iterator = new AppendIterator;
 $iterator->append($array_a);
 $iterator->append($array_b);

 foreach ($iterator as $key => $current) {
     echo $iterator->getIteratorIndex() . '  ' . $key . ' ' . $current . PHP_EOL;
 }
 ?>

The above example will output:

0  a aardwolf
0  b bear
0  c capybara
1  0 apple
1  1 orange
1  2 lemon
AppendIterator::key

AppendIterator::key — Gets the current key

Example #1 AppendIterator::key() basic example

File: AppendIterator_key.php

<?php
 $array_a = new ArrayIterator(array('a' => 'aardwolf', 'b' => 'bear', 'c' => 'capybara'));
 $array_b = new ArrayIterator(array('apple', 'orange', 'lemon'));

 $iterator = new AppendIterator;
 $iterator->append($array_a);
 $iterator->append($array_b);

 // Manual iteration
 $iterator->rewind();
 while ($iterator->valid()) {
     echo $iterator->key() . ' ' . $iterator->current() . PHP_EOL;
     $iterator->next();
 }

 echo PHP_EOL;

 // With foreach
 foreach ($iterator as $key => $current) {
     echo $key . ' ' . $current . PHP_EOL;
 }
 ?>

The above example will output:

The above example will output:

a aardwolf
b bear
c capybara
0 apple
1 orange
2 lemon

a aardwolf
b bear
c capybara
0 apple
1 orange
2 lemon

FilterIterator

By now you should be getting in the swing of iterators. The FilterIterator is and abstract class and is the same as other iterators and we can also overload the FilterIterator class by extending it. This allows us to filter out any unwanted data from our aggregate structure, in this case an array of elements from the periodic table. First, lets look at the available methods to the FilterIterator. The FilterIterator is perhaps the easiest of all iterators to use. Simply by calling the accept method and specifying your filter requirements there.

File: get_filter_iterator_methods.php

<?php
 /*** list all class methods ***/
 foreach( get_class_methods(FilterIterator) as $methodName)
 {
 echo $methodName.'<br />';
 }
 ?>

The snippet above will produce a list of methods in the FilterIterator like this:

__construct

rewind

valid

key

current

next

getInnerIterator

accept

This list should look rather familiar by now as we see it is basically a simple iterator with a few only a fewextra methods. The method we are most concerned with here is the accept() method. By implementing the accept method we can filter out all but the information we want, or do not want. We can even make changes to data within the accept method. Here we will extend the FilterIterator class and use the accept method to cull a few kiwis from an array of Australian natives.

File: File: filter_iterator_accept1.php

<?php
 /*** a simple array ***/
 $animals = array('koala', 'kangaroo', 'wombat', 'wallaby', 'emu', 'NZ'=>'kiwi', 'kookaburra', 'platypus');

 class CullingIterator extends FilterIterator{

 /*** The filteriterator takesa iterator as param: ***/
 public function __construct( Iterator $it ){
 parent::__construct( $it );
 }

 /*** check if key is numeric ***/
 function accept(){
 return is_numeric($this->key());
 }

 }/*** end of class ***/
 $cull = new CullingIterator(new ArrayIterator($animals));

 foreach($cull as $key=>$value)
 {
 echo $key.' == '.$value.'<br />';
 }
 ?>

The above code will produce a list as follows:

0 == koala

1 == kangaroo

2 == wombat

3 == wallaby

4 == emu

5 == kookaburra

6 == platypus

As we iterate over the array the accept() method is called to see wether the current key is valid, in this case, if it is numeric as checked with the PHP is_numeric() function. should be accepted. Of course we could do other tricks within the accept method as seen here as we filter out the prime numbers from an array of numbers.

File: filter_iterator_accept3.php

<pre><?php

class PrimeFilter extends FilterIterator{

/*** The filteriterator takesa iterator as param: ***/
public function __construct(Iterator $it){
parent::__construct($it);
}

/*** check if current value is prime ***/
function accept(){
if($this->current() % 2 != 1)
{
return false;
}
$d = 3;
$x = sqrt($this->current());
while ($this->current() % $d != 0 && $d < $x)
{
$d += 2;
}
 return (($this->current() % $d == 0 && $this->current() != $d) * 1) == 0 ? true : false;
}

}/*** end of class ***/

/*** an array of numbers ***/
$numbers = range(212345,212456);

/*** create a new FilterIterator object ***/
$primes = new primeFilter(new ArrayIterator($numbers));

foreach($primes as $value)
{
echo $value.' is prime.<br />';
}
?>

From the above code we get a list of the prime numbers between 212345 and 212456 as shown here:
212353 is prime.

212369 is prime.

212383 is prime.

212411 is prime.

212419 is prime.

212423 is prime.

212437 is prime.

212447 is prime.

212453 is prime.

This sort of filtering makes the FilterIterator quite a useful tool for aggregate stuctures. Remember, the data could be XML or database results and with the FilterIterator you can specify whatever rules you like in the accept() method. The job of the accept() method is to decide whether an element of the inner iterator should be accessible through the Filteriterator. The inner iterator in the case above is the ArrayIterator.

Oh, and if you think you have a better prime number checking algorithm, please submit it and we will include it.

FilterIterator::accept Another Example
FilterIterator::accept — Check whether the current element of the iterator is acceptable

Example #1 FilterIterator::accept() example

File: filter_iterator_accept2.php

<?php
 // This iterator filters all values with less than 10 characters
 class LengthFilterIterator extends FilterIterator {

     public function accept() {
         // Only accept strings with a length of 10 and greater
         return strlen(parent::current()) > 10;
     }

 }

 $arrayIterator = new ArrayIterator(array('test1', 'more than 10 characters'));
 $lengthFilter = new LengthFilterIterator($arrayIterator);

 foreach ($lengthFilter as $value) {
     echo $value . "\n";
 }
 ?>

The above example will output:

more than 10 characters

There are many ways to iterate over a collection of items, but you might not want to display everything at any given time; say hello to the FilterIterator, a abstract class that have one function you will need to implement: accept.

<?php
/**
 * Our filter, it implements the accept() function,
 * this is where we decide what will be accepted by
 * the foreach further down
 */
class Filter extends FilterIterator {
    /**
     * The filteriterator needs a iterator as param:
     */public function __construct( Iterator $it ) {
        parent::__construct( $it );
    }

    /**
     *  When we iterate over the array the following
     *  function will be called to see wether we should
     *  accept the current key:
     */public function accept() {
        if( preg_match( "/^php/", $this->getInnerIterator()->key() ) ) {
                       return true;
        }
        return false;
    }
}

$arr = array(
    "php" => "php.net",
    "php_pecl" => "pecl.php.net",
    "perl" => "perl.org",
    "python" => "python.org"
);

$obj = new ArrayObject( $arr );

$it = new Filter( $obj->getIterator() );

foreach( $it as $key => $value ) {
        echo "key=$key, value=$value\n";
}
?>

Running this will give us ( as we would suspect ) the following:

key=php, value=php.net
key=php_pecl, value=pecl.php.net

And we have successfully filtered out anything where the key doesn’t start with php.
A FilterIterator can be very useful when you are iterating over items and want to automaticly check the current item before outputting it ( a “adult filter” can be one example of what you want to implement ).

Hi, My name is Masud Alam, love to work with Open Source Technologies, living in Dhaka, Bangladesh. I’m a Certified Engineer on ZEND PHP 5.3, I served my first five years a number of leadership positions at Winux Soft Ltd, SSL Wireless Ltd, Canadian International Development Agency (CIDA), World Vision, Care Bangladesh, Helen Keller, US AID and MAX Group where I worked on ERP software and web development., but now i’m a founder and CEO of TechBeeo Software Company Ltd. I’m also a Course Instructor of ZCPE PHP 7 Certification and professional web development course at w3programmers Training Institute – a leading Training Institute in the country.

2 comments on “Introduction to Standard PHP Library-SPL Part-1
  1. Hi, Thank you for this examples. Very helpful.

    I have a question:
    if i comment out the line below in the filter iterator example, the code still works. Should I include that? if yes, why?

    code i commented out:
    /*** The filteriterator takesa iterator as param: ***/
    public function __construct( Iterator $it ){
    parent::__construct( $it );
    }

Leave a Reply

Your email address will not be published. Required fields are marked *