আগামী ১৫ ডিসেম্বর -২০১৭ তারিখ থেকে শুরু হচ্ছে পাঁচ মাস ব্যাপী 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-3

Standard PHP Library

After completing SPL part1 and SPL part2, In this tutorial  Now we learn  Caching Iterator,ArrayObject and ArrayIterators. 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

Caching Iterator

The caching Iterator is a forward seeking iterator and is useful for lookng forward to check if there is a valid next item.

This note from the PHP source best describes what it can do

  • note If you want to convert the elements into strings and the inner
  • * Iterator is an internal Iterator then you need to provide the
  • * flag CIT_CALL_TOSTRING to do the conversion when the actual element
  • * flag CALL_TOSTRING to do the conversion when the actual element
  • * is being fetched. Otherwise the conversion would happen with the
  • * already changed iterator. If you do not need this then it you should
  • * omit this flag because it costs unneccessary work and time.

Once again we will see what methods are available to the iterator.

File: get_caching_iterator_methods.php

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

From the above we get a list like this…

  • construct
  • rewind
  • valid
  • key
  • current
  • next
  • hasNext
  • __toString
  • getInnerIterator
  • getFlags
  • setFlags
  • offsetGet
  • offsetSet
  • offsetUnset
  • offsetExists
  • getCache

Some of the above methods will look very familiar by now. These include rewind(), valid(), current() and the usual suspects. But the CachingIterator also brings a few additions with hasNext and __toString and others. Lets begin with the hasNext() method. For the sake of example, we want our array to be formatted for use in a CSV file. This means we need a comma (,) after each member, except the last one. Traditionally we would have needed to do something like this…

File: caching_iterator1.php

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

 /*** set a counter ***/
 $c = 1;

 /*** count how many members are in the array ***/
 $count = count($array);

 /*** loop of the array ***/
 foreach($array as $value)
 {
 echo $value;
 if($c < $count)
 {
 echo ',';
 $c++;
 }
 }
 ?>

Apart from being plain ugly, the use of foreach here creates memory issues when it creates a copy of the array. Because SPL iterators know only one element at a time, it is far more efficient. Lets see how SPL deals with the same task.

File: caching_iterator2.php

[/php]

<?php
/*** a simple array ***/
$array = array(‘koala’, ‘kangaroo’, ‘wombat’, ‘wallaby’, ’emu’, ‘kiwi’, ‘kookaburra’, ‘platypus’);

try {
/*** create a new object ***/
$object = new CachingIterator(new ArrayIterator($array));
foreach($object as $value)
{
echo $value;
if($object->hasNext())
{
echo ‘,’;
}
}
}
catch (Exception $e)
{
echo $e->getMessage();
}
?>

[/php]

This makes for much cleaner code by ridding us of counters and the like, we could further make this code more re-usable by extending the CachingIterator class. This would be most helpful if this task was something that needed to be done on a regular basis.

File: caching_iterator3.php

<?php

 class addComma extends CachingIterator{

 /*** add a comma if there is more array members ***/
 function current(){
 if(parent::hasNext())
 {
 return parent::current().',';
 }
  else
 {
 return parent::current();
 }
 }

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

 /*** a simple array ***/
 $array = array('koala', 'kangaroo', 'wombat', 'wallaby', 'emu', 'kiwi', 'kookaburra', 'platypus');

 try {
 /*** create a new object ***/
 $object = new addComma(new ArrayIterator($array));
 foreach($object as $value)
 {
 echo $value;
 }
 }
 catch (Exception $e)
 {
 echo $e->getMessage();
 }
 ?>

We see from the above script that the same result is achieved but the code base is now a re-usable class extension. If we wanted access to the inner iterator, ie. ArrayIterator, we could use the getInnerIterator() method to do so.

File: caching_iterator4.php

<?php

 class addComma extends CachingIterator{
 /*** overload the current method ***/
 function current(){
 if(parent::hasNext())
 {
 return parent::current().',';
 }
  else
 {
 return parent::current();
 }
 }

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

 /*** a simple array ***/
 $array = array('koala', 'kangaroo', 'wombat', 'wallaby', 'emu', 'kiwi', 'kookaburra', 'platypus');

 try {
 /*** create a new object ***/
 $object = new addComma(new ArrayIterator($array));
 $object->getInnerIterator()->offsetUnset(5);
 foreach($object as $value)
 {
 echo $value;
 }
 }
 catch (Exception $e)
 {
 echo $e->getMessage();
 }
 ?>

The above results produce a list of animals minus the array member 5, the kiwi. we used the getInnerIterator() method to directly access the inner iterator, in this case the ArrayIterator, which gives us access to all the fun methods associated with that iterator. However, this still may not be optimal for re-use. We could call the inner iterator from our extended class and deal with the offending kiwi there, thus streamlining our userland codebase.

File: caching_iterator5.php

<?php

 class addComma extends CachingIterator{

 function __construct($it){
 /*** pass the iterator to the parent ***/
 parent::__construct($it);
 /*** call the parent getInnerIterator class method offSetUnset() ***/
 parent::getInnerIterator()->offSetUnset(5);
 }

 function current(){
 if(parent::hasNext())
 {
 return parent::current().',';
 }
  else
 {
 return parent::current();
 }
 }

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

 /*** a simple array ***/
 $array = array('koala', 'kangaroo', 'wombat', 'wallaby', 'emu', 'kiwi', 'kookaburra', 'platypus');

 try {
 /*** create a new object ***/
 $object = new addComma(new ArrayIterator($array));
 foreach($object as $value)
 {
 echo $value;
 }
 }
 catch (Exception $e)
 {
 echo $e->getMessage();
 }
 ?>

Now we see how extensible SPL really is. The same concepts can be used with all iterators when extending. The CachingIterator also has a number of flags for use with the iterator. They are..

  • CALL_TOSTRING
  • TOSTRING_USE_KEY
  • TOSTRING_USE_CURRENT
  • TOSTRING_USE_INNER

The CALL_TOSTRING flag is quite simple as it simply calls __toString() method.

File: caching_iterator6.php

<?php

 /*** a simple array ***/
 $array = array('koala', 'kangaroo', 'wombat', 'wallaby', 'emu', 'kiwi', 'kookaburra', 'platypus');
 /*** a new caching iterator object ***/
 $cacheObj = new CachingIterator(new ArrayIterator($array), 0);
 try
 {
 /*** set the flag __toString ***/
 $cacheObj->setFlags(CachingIterator::CALL_TOSTRING);
 /*** loop through the object ***/
 foreach($cacheObj as $v)
  {
  /*** object is now cast to string ***/
  echo(string)$cacheObj.'<br />';
  }
 }
 catch (Exception $e)
 {
 echo 'Exception: ' . $e->getMessage();
 }
 ?>

As seen above, the object has been made into a string representation and can be used directly as a string. Note also we have used the CachingIterator::setFlags() method to set the flag. We use the TOSTRING_USE_KEY in the same way. This flag will call the array keys as shown below.

File: caching_iterator7.php

<?php

 /*** a simple array ***/
 $array = array('koala', 'kangaroo', 'wombat', 'wallaby', 'emu', 'kiwi', 'kookaburra', 'platypus');
 /*** a new caching iterator object ***/
 $cacheObj = new CachingIterator(new ArrayIterator($array), 0);
 try
 {
 /*** set the flag __toString ***/
 $cacheObj->setFlags(CachingIterator::TOSTRING_USE_KEY);
 /*** loop through the object ***/
 foreach($cacheObj as $v)
  {
  /*** object is now cast to string ***/
  echo(string)$cacheObj.'<br />';
  }
 }
 catch (Exception $e)
 {
 echo 'Exception: ' . $e->getMessage();
 }
 ?>

The TOSTRING_USE_KEY flag has been used to grab the array keys from the caching iterator object, and force them into a string representation. So the result from the above code will yield the numbers 0-7. Not too exciting, but remember, iterators can be used to traverse ANY aggregate structure, so if the above principles were applied to an XML document, or a result set from a database query, you can quickly see how this might be useful. Finally the TOSTRING_USE_CURRENT is once again used in the same manner as shown here.

File: caching_iterator8.php

<?php

 /*** a simple array ***/
 $array = array('koala', 'kangaroo', 'wombat', 'wallaby', 'emu', 'kiwi', 'kookaburra', 'platypus');
 /*** a new caching iterator object ***/
 $cacheObj = new CachingIterator(new ArrayIterator($array), 0);
 try
 {
 /*** set the flag __toString ***/
 $cacheObj->setFlags(CachingIterator::TOSTRING_USE_CURRENT);
 /*** loop through the object ***/
 foreach($cacheObj as $v)
  {
  /*** object is now cast to string ***/
  echo(string)$cacheObj.'<br />';
  }
 }
 catch (Exception $e)
 {
 echo 'Exception: ' . $e->getMessage();
 }
 ?>

The TOSTRING_USE_INNER flag is used to call the __toString() method from an inner iterator object. Lets put it to work and then see you the results.

File: caching_iterator9.php

[/php]

<?php

/*** a simple array ***/
$array = array(‘koala’, ‘kangaroo’, ‘wombat’, ‘wallaby’, ’emu’, ‘kiwi’, ‘kookaburra’, ‘platypus’);

/*** a new caching object ***/
$cacheObj = new CachingIterator(new MyArrayIterator($array), 0);
try
{
/*** set our flags ***/
$cacheObj->setFlags(CachingIterator::TOSTRING_USE_INNER);
/*** travers the iterator ***/
foreach($cacheObj as $v)
{
/*** objects are now strings ***/
echo (string)$cacheObj.'<br />’;
}
}
catch (Exception $e)
{
echo ‘Exception: ‘ . $e->getMessage() . “\n”;
}

class MyArrayIterator extends ArrayIterator
{
function __toString(){
return $this->key() . ‘:’ . $this->current();
}

}/*** end of class ***/
?>

[/php]

The TOSTRING_USE_INNER flag has been set and so the __toString() method has been called from the inner interator object. The inner iterator object in this case is formed from the thte MyArrayIterator class which extends ArrayIterator. The MyArrayIterator::__toString() method has been used to return a string representation of the current key and value. This results in a list such as this.

  • 0:koala
  • 1:kangaroo
  • 2:wombat
  • 3:wallaby
  • 4:emu
  • 5:kiwi
  • 6:kookaburra
  • 7:platypus

Note: you can only use ONE flag for the __toString() method. If you try to use more an exception will be thrown.

File: caching_iterator10.php

<?php

 class MyCachingIterator extends CachingIterator{

 function __construct(Iterator $it, $flags = 0){
 parent::__construct($it, $flags);
 }

 function test($offsetArray){
 foreach($offsetArray as $offset)
 {
 if($this->offsetExists($offset));
 {
 echo $offset.' == '. $this->offsetGet($offset).'<br />';
 }
 }
 }
 }/*** end of class ***/

 /*** a simple array ***/
 $array = array('koala', 'kangaroo', 'wombat', 'wallaby', 'emu', 'NZ'=>'kiwi', 'kookaburra', 'platypus');
 try {

 $it = new MyCachingIterator(new ArrayIterator($array), CachingIterator::FULL_CACHE);

 /*** an array of checks to run ***/
 $offsetArray = array(0, 2, 'NZ', 3 , 6);

 /*** read all into cache ***/
 foreach($it as $v);

 /*** load the offset array ***/
 $it->test($offsetArray);
 }
 catch(Exception $e)
 {
 echo $e->getMessage();
 }
 ?>

There may be a bit to digest from the code above. But essentially it checks the offsets in offsetArray and prints the values like this.

  • 0 == koala
  • 2 == wombat
  • NZ == kiwi
  • 3 == wallaby
  • 6 == platypus

So, there is a little WTF value here. We have used offsetExists to check the values of the offsetArray and offsetGet to print the value of the offset. You will have noticed that the offset of 6 is platypus. This is because there is no offset of 7 as the fifth offset is NZ with the value of kiwi. So offset 5 becomes the next offset and 6 is the final offset in this array.

The offsetUnset() method has been left to now for the reason of explaining some internal behaviour that may not be apparent other wise. When an offset is unset, only the value of the offset is unset and the offset/key remains. In the cache however, the offset and key are removed. The script below shows clearly the behavior when the cache is called with the getCache() method.

File: caching_iterator11.php

<?php

 class MyCachingIterator extends CachingIterator{

 function __construct(Iterator $it, $flags = 0){
 parent::__construct($it, $flags);
 }

 function test($offsetArray){
 /*** check if the offset exists ***/
 if($this->offsetExists('NZ'));
 {
 /*** unset the offset ***/
 $this->offsetUnset('NZ');
 }
 /*** loop over the $offset array ***/
 foreach($offsetArray as $offset)
 {
 /*** get the corresponding value of the offset ***/
 echo $offset.' == '. $this->offsetGet($offset).'<br />';
 }
 }
 }/*** end of class ***/

 /*** a simple array ***/
 $array = array('koala', 'kangaroo', 'wombat', 'wallaby', 'emu', 'NZ'=>'kiwi', 'kookaburra', 'platypus');
 try {

 $it = new MyCachingIterator(new ArrayIterator($array), CachingIterator::FULL_CACHE);

 /*** an array of checks to run ***/
 $offsetArray = array(0, 2, 'NZ', 3 , 6);

 /*** read all into cache ***/
 foreach($it as $v);

 /*** load the offset array ***/
 $it->test($offsetArray);

 /*** show the cache contents ***/
 echo '<h3>Get Cache</h3>';
 foreach($it->getCache() as $offset=>$value)
 {
 echo 'Cache: '.$offset.' == '.$value.'<br />';
 }
 }
 catch(Exception $e)
 {
 echo $e->getMessage();
 }
 ?>

The results from the above code will produce the following output.

0 == koala
2 == wombat
NZ ==
3 == wallaby
6 == platypus

Get Cache

Cache: 0 == koala
Cache: 1 == kangaroo
Cache: 2 == wombat
Cache: 3 == wallaby
Cache: 4 == emu
Cache: 5 == kookaburra
Cache: 6 == platypus

Note that in the first iteration, the NZ key remains and the value has been removed. When the cache itself is checked with getCache we see the true picture of the current state of the offset keys and values. The array object has been re-indexed with the NZ offset key and value removed.

ArrayObject

The ArrayObject allows for external traversal of arrays and to create instances of ArrayIterator. Much like the Directory Iterator, we can see the methods available to the Array Iterator with a simple snippet.

<?php
 foreach(get_class_methods(new ArrayObject()) as $key=>$method)
 {
 echo $key.' -> '.$method.'<br />';
 }
 ?>

Again we see the class methods in a list as follows.

  • 0 -> __construct
  • 1 -> offsetExists
  • 2 -> offsetGet
  • 3 -> offsetSet
  • 4 -> offsetUnset
  • 5 -> append
  • 6 -> getArrayCopy
  • 7 -> count
  • 8 -> getFlags
  • 9 -> setFlags
  • 10 -> asort
  • 11 -> ksort
  • 12 -> uasort
  • 13 -> uksort
  • 14 -> natsort
  • 15 -> natcasesort
  • 16 -> getIterator
  • 17 -> exchangeArray
  • 18 -> setIteratorClass
  • 19 -> getIteratorClass

We will see in the following code snippets, various ways to use some of these methods along with the ArrayIterator class. First a simple ArrayObject and ArrayIterator.

<?php

 /*** a simple array ***/
 $array = array('koala', 'kangaroo', 'wombat', 'wallaby', 'emu', 'kiwi', 'kookaburra', 'platypus');

 /*** create the array object ***/
 $arrayObj = new ArrayObject($array);

 /*** iterate over the array ***/
 for($iterator = $arrayObj->getIterator();
  /*** check if valid ***/
  $iterator->valid();
  /*** move to the next array member ***/
  $iterator->next())
     {
     /*** output the key and current array value ***/
     echo $iterator->key() . ' => ' . $iterator->current() . '<br />';
     }
 ?>

In the above script we have externally traversed the array object with getIterator(). We could have used a foreach on the array and the getInstance() method would be called implicitly. The key() and current() methods also belong to the ArrayIterator Instance. From the above code snippet we get a simple array output as follows

  • 0 => koala
  • 1 => kangaroo
  • 2 => wombat
  • 3 => wallaby
  • 4 => emu
  • 5 => kiwi
  • 6 => kookaburra
  • 7 => platypus

You might be getting the swing of this by now, so to keep it simple we will use the same code from above and append, or add, a value to the array and iterate over it. Note that the ArrayObject::getIterator returns an ArrayIterator instance working on the original ArrayObject instance. It’s only method getIterator() is automatically called in iteration, thus if you put an ArrayObject which implements that interface into a foreach() construct that method is being executed automatically. Since the ArrayObject returns an ArrayIterator interface the foreach() Construct will reset that iterator and work on it.

 <?php

 /*** a simple array ***/
 $array = array('koala', 'kangaroo', 'wombat', 'wallaby', 'emu', 'kiwi', 'kookaburra', 'platypus');

 /*** create the array object ***/
 $arrayObj = new ArrayObject($array);

 /*** append a value to the array ***/
 $arrayObj->append('dingo');

 /*** iterate over the array ***/
 for($iterator = $arrayObj->getIterator();
  /*** check if valid ***/
  $iterator->valid();
  /*** move to the next array member ***/
  $iterator->next())
 {
 /*** output the key and current array value ***/
 echo $iterator->key() . ' -> ' . $iterator->current() . '<br />';
 }
 ?>

Now we see that the list has the value ‘dingo’ on the end of it and we begin to see the usefulness of an Object Oriented approach. Our list looks like this.
0 -> koala
1 -> kangaroo
2 -> wombat
3 -> wallaby
4 -> emu
5 -> kiwi
6 -> kookaburra
7 -> platypus
8 -> dingo

We can sort the array with one of the array sort methods available to the array object. In this instance, we will sort alphabetically using the natcasesort() method.

<?php

 /*** a simple array ***/
 $array = array('koala', 'kangaroo', 'wombat', 'wallaby', 'emu', 'kiwi', 'kookaburra', 'platypus');

 /*** create the array object ***/
 $arrayObj = new ArrayObject($array);

 /*** sort alphabetically ***/
 $arrayObj->natcasesort();

 /*** iterate over the array ***/
 for($iterator = $arrayObj->getIterator();
  /*** check if valid ***/
  $iterator->valid();
  /*** move to the next array member ***/
  $iterator->next())
 {
 /*** output the key and current array value ***/
 echo $iterator->key() . ' -> ' . $iterator->current() . '<br />';
 }
 ?>

Now we see our array has changed and the output now looks like this:
4 -> emu
1 -> kangaroo
5 -> kiwi
0 -> koala
6 -> kookaburra
7 -> platypus
3 -> wallaby
2 -> wombat
As you can see, the order has changed but not the keys. We could sort them similarly with asort, usort or any of the other sorting methods listed by get_class_methods(). To see a count of the total number of members in our array object is a trivial matter of using the count() method as shown below.

<?php

 /*** a simple array ***/
 $array = array(\koala\, \kangaroo\, \wombat\, \wallaby\, \emu\, \kiwi\, \kookaburra\, \platypus\);

 /*** create the array object ***/
 $arrayObj = new ArrayObject($array);

 /*** echo the total number of elements ***/
 echo $arrayObj->count();
 ?>

We see the return value from the count() method is 8. We may also note that one of the beasts in our array of animals does not belong. This is an array of animals native to Australia (straya), but the kiwi is a New Zealand critter. To remove this undesirable from the array we use theoffsetUnset() method. Lets see how it works.

<?php

 /*** a simple array ***/
 $array = array('koala', 'kangaroo', 'wombat', 'wallaby', 'emu', 'kiwi', 'kookaburra', 'platypus');

 /*** create the array object ***/
 $arrayObj = new ArrayObject($array);
 /*** unset the array member ***/
 $arrayObj->offsetUnset(5);

 /*** loop of the array object ***/
 for($iterator = $arrayObj->getIterator();
  /*** check if valid ***/
  $iterator->valid();
  /*** move to the next array member ***/
  $iterator->next())
 {
 /*** output the key and current array value ***/
 echo $iterator->key() . ' -> ' . $iterator->current() . '<br />';
 }
 ?>

The above code will produce this output..
0 -> koala
1 -> kangaroo
2 -> wombat
3 -> wallaby
4 -> emu
6 -> kookaburra
7 -> platypus
The offending New Zealand critter has been removed from the array but the array is not re-indexed.

To check for the existance of an offset within the array, we use the offsetExists() method as demonstrated below.

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

 /*** create the array object ***/
 $arrayObj = new ArrayObject($array);

  if ($arrayObj->offsetExists(3))
 {
 /*** unset the key ***/
 echo 'Offset Exists</br />';
 }
 ?>

The above snippet tells us the offset Exists and runs the code in the if{} block. This has the same functionality as array_key_exists(). It is possible to change the value of an array member with the offsetSet method. Here we show how by changing the kiwi to the Australian native bird ‘galah’.

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

 try {
 /*** create the array object ***/
 $arrayObj = new ArrayObject($array);

 /*** set the offset of 5 to a new value ***/
 $arrayObj->offsetSet(5, "galah");

 /*** loop of the array object ***/
 for($iterator = $arrayObj->getIterator();
 /*** check if valid ***/
 $iterator->valid();
 /*** move to the next array member ***/
 $iterator->next())
 {
 /*** output the key and current array value ***/
 echo $iterator->key() . ' -> ' . $iterator->current() . '<br />';
 }
 }
 catch (Exception $e)
 {
 echo $e->getMessage();
 }
 ?>

We see that when we iterate over the array object the kiwi has been set to ‘galah’. We can also get a value from the array object by using the offsetGet() method.

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

try {
 /*** create the array object ***/
 $arrayObj = new ArrayObject($array);

/*** echo the value of the array object 4 ***/
 echo $arrayObj->offsetGet(4);
 }
 catch(Exception $e)
 {
 echo $e->getMessage();
 }
 ?>

The script above prints ’emu’ as this is the value of the offset 4.

There are times you may need a copy of an array to edit or to do comparisons, to this end the method getArrayCopy() is provided for just that purpose. Here we show a simple array copy.

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

 try {
 /*** create the array object ***/
 $arrayObj = new ArrayObject($array);

 /*** create a copy of the array object ***/
 $arrayObjCopy = $arrayObj->getArrayCopy();

 /*** iterate over the array copy ***/
 for($iterator = $arrayObjCopy->getIterator();
 /*** check if valid ***/
 $iterator->valid();
 /*** move to the next array member ***/
 $iterator->next())
 {
 /*** output the key and current array value ***/
 echo $iterator->key() . ' => ' . $iterator->current() . '<br />';
 }
 }
 catch (Exception $e)
 {
 echo $e->getMessage();
 }
 ?>

When you run the above code you will get an error message similar to this..
Fatal error: Call to a member function getIterator() on a non-object in /www/spl.php on line 13
This is because the copy of the array is just a copy of the array, it is NOT an array object that SPL can iterate over, so we must create a new array object as shown here:

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

 try {
 /*** create the array object ***/
 $arrayObj = new ArrayObject($array);

 /*** create a copy of the array object
 you MUST create a new array object also ***/
 $arrayObjCopy = new ArrayObject($arrayObj->getArrayCopy());

 /*** iterate over the array copy ***/
 for($iterator = $arrayObjCopy->getIterator();
 /*** check if valid ***/
 $iterator->valid();
 /*** move to the next array member ***/
 $iterator->next())
 {
 /*** output the key and current array value ***/
 echo $iterator->key() . ' -> ' . $iterator->current() . '<br />';
 }
 }
 catch (Exception $e)
 {
 echo $e->getMessage();
 }
 ?>

Now of course, we can safely iterate over the newly create array and array object, the results will be as before:
0 -> koala
1 -> kangaroo
2 -> wombat
3 -> wallaby
4 -> emu
5 -> kiwi
6 -> kookaburra
7 -> platypus

The ArrayObject class also comes with several flags..

  • ARRAY_AS_PROPS
  • STD_PROP_LIST

These flags are quite funky the ARRAY_AS_PROPS constant allows array indexes to be accessed as properties in read/write, while the STD_PROP_LIST allows properties of the object to have their normal functionality. Lets begin with a short demonstration of ARRAY_AS_PROPS.

<?php

?>

ArrayIterator

If you have not read the previous section on ArrayObject it is highly recommended you do so, as this section is really an addition to the previous where we have been using the ArrayIterator to traverse ArrayObjects.. The ArrayIterator makes use of the ArrayObject to traverse arrays and an understanding of this is important. Much like the Directory Iterator, we can see the methods available to the Array Iterator with a simple snippet.

<?php

 foreach(get_class_methods(new ArrayIterator()) as $key=>$method)
 {
 echo $key.' -> '.$method.'<br />';
 }
 ?>

The above snippet will produce a list of methods available to the ArrayIterator class as shown below.

  • 0 -> __construct
  • 1 -> offsetExists
  • 2 -> offsetGet
  • 3 -> offsetSet
  • 4 -> offsetUnset
  • 5 -> append
  • 6 -> getArrayCopy
  • 7 -> count
  • 8 -> getFlags
  • 9 -> setFlags
  • 10 -> asort
  • 11 -> ksort
  • 12 -> uasort
  • 13 -> uksort
  • 14 -> natsort
  • 15 -> natcasesort
  • 16 -> rewind
  • 17 -> current
  • 18 -> key
  • 19 -> next
  • 20 -> valid
  • 21 -> seek

Remember the ‘S’ in SPL is for ‘Standard’ and here we see why. From here, using the ArrayIterator is quite simple given any array. Here we iterate over a simple array and output the variables to the browser. The ArrayIterator takes an ArrayObject as its arguement, so, before we can use the ArrayIterator class we must create the ArrayObject to be able to iterate over it.

We have already seen the ArrayIterator in action with the ArrayObject. Lets see a simple array iteration.

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

 try {
 /*** create a new object ***/
 $object = new ArrayIterator($array);
 /*** rewind to the beginning of the array ***/
 $object->rewind();
 /*** check for valid member ***/
 while($object->valid())
 {
 /*** echo the key and current value ***/
 echo $object->key().' -&gt; '.$object->current().'<br />';
 /*** hop to the next array member ***/
 $object->next();
 }
 }
 catch (Exception $e)
 {
 echo $e->getMessage();
 }
 ?>

Of course, the script above iterates over the array and produces a list of the array keys and values, it shows how we have manually called the ArrayIterator to traverse the array of animals. We could however, call the ArrayIterator implicitly like this:

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

 try {
 $object = new ArrayIterator($array);
 foreach($object as $key=>$value)
 {
 echo $key.' => '.$value.'<br />';
 }
 }
 catch (Exception $e)
 {
 echo $e->getMessage();
 }
 ?>

Above we see the ArrayIterator is implicitly used but we the difference is hidden from us. A traditional array traversal allocates every member of the array to memory. The iterator assigns memory for the current element only. This can be a huge benifit when dealing with large arrays.

Array offsets may be checked for and acquired using the offSetExists() and offSetGet() methods as shown below.

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

 try {
 $object = new ArrayIterator($array);
 if($object->offSetExists(2))
 {
 echo $object->offSetGet(2);
 }
 }
 catch (Exception $e)
 {
 echo $e->getMessage();
 }
 ?>

The above code checks for the existence of the offset 2 with the offSetExists() method. When it is found, the value of the offset is used to display it using offSetGet(). We can also set and unset array members within the array.

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

 try {
 $object = new ArrayIterator($array);
 /*** check for the existence of the offset 2 ***/
 if($object->offSetExists(2))
 {
 /*** set the offset of 2 to a new value ***/
 $object->offSetSet(2, 'Goanna');
 }
  /*** unset the kiwi ***/
  foreach($object as $key=>$value)
 {
 /*** check the value of the key ***/
 if($object->offSetGet($key) === 'kiwi')
 {
 /*** unset the current key ***/
 $object->offSetUnset($key);
 }
 echo '<li>'.$key.' - '.$value.'</li>'."\n";
 }
 }
 catch (Exception $e)
 {
 echo $e->getMessage();
 }
 ?>
 </ul>

Now we see some interesting behaviour along with our expected behaviour. Using the offsetSet() method the value at the offset of 2 has been changed from wombat to Goanna. A simple foreach to iterate over the array. The output looks like this..

  • 0 – koala
  • 1 – kangaroo
  • 2 – Goanna
  • 3 – wallaby
  • 4 – emu
  • 5 – kiwi
  • 1 – kangaroo
  • 2 – Goanna
  • 3 – wallaby
  • 4 – emu
  • 6 – kookaburra
  • 7 – platypus

Notice here how the Iterator pointer has been re-wound back to the beginning of the array when we used the offsetUnset() method to unset the array whose key had the value of kiwi. The iteration begins again and as you can see, the key of 5 with the value of kiwi is missing from the object. The internal point can be re-wound intentionally should we wish, using the rewind() method.

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

 try {
 /*** create a new iterator object ***/
 $object = new ArrayIterator($array);
 /*** iterate over the array ***/
 foreach($object as $key=>$value)
 {
 echo $value.'<br />';
 }
 /*** rewind the internal pointer ***/
 $object->rewind();
 /*** echo the current array member ***/
 echo $object->current();
 }
 catch (Exception $e)
 {
 echo $e->getMessage();
 }

?>

The code above will produce a list like this:

koala
kangaroo
wombat
wallaby
emu
kiwi
kookaburra
platypus
koala

The Iterator has traversed the array successfully, then we have used the $object->rewind method to rewind the internal pointer back to the beginning of the array and display the value of the current member, which is koala.

If we wanted to get the size of the object, it is a trivial matter of using the count method as follows.

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

 try {
 /*** create a new iterator object ***/
 $object = new ArrayIterator($array);
 /*** get the size of the object ***/
 echo $object->count();
 }
 catch (Exception $e)
 {
 echo $e->getMessage();
 }
 ?>

The above will return a value of 8 as there are 8 members in our array object.

Recursive Array Iterator

The array Iterator above is great for traversing single dimensional arrays. Of course not all arrays are like this, quite often we are presented with a multi-dimensional array. In the bad old days to get around this we might have used 2 foreach() loops, which would have been very costly. To traverse a multi-dimensional array we use the RecursiveArrayIterator(). Let’s take a quick at how it looks.

<?php

 /*** an array of animal ***/
 $animals = array(
 array('type'=>'dog', 'name'=>'butch', 'sex'=>'m', 'breed'=>'boxer'),
 array('type'=>'dog', 'name'=>'fido', 'sex'=>'m', 'breed'=>'doberman'),
 array('type'=>'dog', 'name'=>'girly','sex'=>'f', 'breed'=>'poodle'),
 array('type'=>'cat', 'name'=>'tiddles','sex'=>'m', 'breed'=>'ragdoll'),
 array('type'=>'cat', 'name'=>'tiddles','sex'=>'f', 'breed'=>'manx'),
 array('type'=>'cat', 'name'=>'tiddles','sex'=>'m', 'breed'=>'maine coon'),
 array('type'=>'horse', 'name'=>'ed','sex'=>'m', 'breed'=>'clydesdale'),
 array('type'=>'perl_coder', 'name'=>'shadda','sex'=>'none', 'breed'=>'mongrel'),
 array('type'=>'duck', 'name'=>'galapogus','sex'=>'m', 'breed'=>'pekin')
 );

 /*** create a new recursive array iterator ***/
 $iterator =new RecursiveArrayIterator(new ArrayObject($animals));
 /*** traverse the $iterator object ***/
 while($iterator->valid())
 {
 echo $iterator->key().' -- '.$iterator->current().'<br/>';
 $iterator->next();
 }
 ?>

The output from the above code will produce the following..

  • 0 — Array
  • 1 — Array
  • 2 — Array

You might be saying WTF! about now as all we see is an array of arrays. This is because we need to iterate recursively over the recursive iterator object. To do this we need an iterator, that will recursively iterate over an iterator. The RecursiveIteratorIterator is the correct tool for this. Lets adjust our code a little to see how it works.

<?php
 $array = array(
 array('name'=>'butch', 'sex'=>'m', 'breed'=>'boxer'),
 array('name'=>'fido', 'sex'=>'m', 'breed'=>'doberman'),
 array('name'=>'girly','sex'=>'f', 'breed'=>'poodle')
 );

 foreach(new RecursiveIteratorIterator(new RecursiveArrayIterator($array)) as $key=>$value)
 {
 echo $key.' -- '.$value.'<br />';
 }
 ?>

In the above code, the RecursiveIteratorIterator() takes an iterator as its argument, in this instance, a RecursiveArrayIterator(), which in turn takes a multi-dimensional array as its arguement. This is a far more graceful way of traversing a multi-dimensional array than we have previously been used to. The above code will now recursively iterate over the multi-dimensional array, and give us output like this below.

  • name — butch
  • sex — m
  • breed — boxer
  • name — fido
  • sex — m
  • breed — doberman
  • name — girly
  • sex — f
  • breed – poodle

Introduction to Standard PHP Library -SPL Part-3

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.

0 comments on “Introduction to Standard PHP Library -SPL Part-3

Leave a Reply

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