Backend DevelopmentIteratorsWeb Development

PHP Iterators Part 2: SPL Array Iterator, Directory Iterator, and Filesystem Iterator

php iterators

In this part of this series (PHP Iterators) we will continue demonstrating iterators. We will talk about SPL iterators and what helpful features it provide out of the box.

 

 

Series Topics:

 

In the previous part of this series we learned about iterators, what they do, what iterators class hierarchy and how to extend them using the Iterator and IteratorAggregate classes to create a custom iterator, also learned how to loop over these iterator classes with the foreach loop as if it be a normal array. If you need to go back and review the previous part just click this link.

 

SPL Iterators

PHP provides a special built in iterators through the SPL extension called SPL Iterators. These SPL Iterators perform a lot of tasks which can be iterators that can be used for filtering arrays, iterators for manipulating directory and filesystem, iterators for recursive operations, and many more.

 

PHP SPL Iterators:

  • AppendIterator
  • ArrayIterator
  • CachingIterator
  • CallbackFilterIterator
  • DirectoryIterator
  • EmptyIterator
  • FilesystemIterator
  • FilterIterator
  • GlobIterator
  • InfiniteIterator
  • IteratorIterator
  • LimitIterator
  • MultipleIterator
  • NoRewindIterator
  • ParentIterator
  • RecursiveArrayIterator
  • RecursiveCachingIterator
  • RecursiveCallbackFilterIterator
  • RecursiveDirectoryIterator
  • RecursiveFilterIterator
  • RecursiveIteratorIterator
  • RecursiveRegexIterator
  • RecursiveTreeIterator
  • RegexIterator

 

Array Iterator

This iterator allows to unset and modify values and keys while iterating over Arrays and Objects. ArrayIterator can be created by passing an array to the constructor. When you want to iterate over the same array multiple times you need to instantiate ArrayObject and let it create ArrayIterator instances that refer to it either by using foreach or by calling its getIterator() method manually.

ArrayIterator implements several interfaces as shown below:

ArrayIterator implements ArrayAccess , SeekableIterator , Countable , Serializable {//...}
    
     const integer STD_PROP_LIST = 1 ;
     const integer ARRAY_AS_PROPS = 2 ;
 
    //. . . snip
    public function asort ( void );
    public function ksort ( void );
    public function natcasesort ( void );
    public function natsort ( void );
    public function uasort ( string $cmp_function );
    public function uksort ( string $cmp_function );
    public string serialize ( void );
}

As shown above ArrayIterator wraps some of the methods that are used to manipulate arrays like sort and serialize.

 

Let’s see an example

<?php
$technologies = array(
    "php" => "web programming",
    "c++" => "general purpose programming",
    "java" => "android programming",
    "swift" => "ios programming",
    "assemply" => "system programming",
);

$arrayIterator = new ArrayIterator($technologies);

echo "<pre>";
foreach ($arrayIterator as $key => $value) {

       echo $key . ' => ' . $value ."\n";
}
echo "</pre">;

 

As shown here if you run the above code it will print the data as if it be an ordinary array. Now if you print_r the arrayIterator object you will see this output:

echo "<pre>";
print_r($arrayIterator);
echo "</pre>";


// output is ArrayIterator object
ArrayIterator Object
(
    [storage:ArrayIterator:private] => Array
        (
            [php] => web programming
            [c++] => general purpose programming
            [java] => android programming
            [swift] => ios programming
            [assemply] => system programming
        )

)

 

Let’s see another example to demonstrate the ArrayIterator methods:

<?php

$data = array('foo', 'bar', 'baz');

// create arrayiterator
$array = new ArrayIterator($data);


echo "<pre>";
$array->offsetUnset(2);   // remove the last element
print_r($array);           


// output
ArrayIterator Object
(
    [storage:ArrayIterator:private] => Array
        (
            [0] => foo
            [1] => bar
        )

)
ArrayIterator Object
(
    [storage:ArrayIterator:private] => Array
        (
            [0] => foo
            [1] => bar
            [3] => foobar
        )

)
number of elements: 3
ArrayIterator Object
(
    [storage:ArrayIterator:private] => Array
        (
            [1] => bar
            [0] => foo
            [3] => foobar
        )

)
ArrayIterator Object
(
    [storage:ArrayIterator:private] => Array
        (
            [0] => foo
            [1] => bar
            [3] => foobar
        )

)
serialized array: x:i:0;a:3:{i:0;s:3:"foo";i:1;s:3:"bar";i:3;s:6:"foobar";};m:a:0:{}

$array->append('foobar');   // append a new element
print_r($array);

// get number of elements
echo "number of elements: " . $array->count() . "<br/>";

$array->asort();             // sorting by value
print_r($array);

$array->ksort();             // sorting by key
print_r($array);

// serializing array
echo "serialized array: " . $array->serialize();

echo "</pre>";

In the above code we showed some of the ArrayIterator methods to sort arrays and serialize, there are a lot of other methods to use, check the php.net manual for a list of method.

 

Another example using the ArrayObject class:

<?php
$fruits = array(
    "apple" => "yummy",
    "orange" => "ah ya, nice",
    "grape" => "wow, I love it!",
    "plum" => "nah, not me"
);
$obj = new ArrayObject( $fruits );
$it = $obj->getIterator();

// How many items are we iterating over?

echo "Iterating over: " . $obj->count() . " values\n";

// Iterate over the values in the ArrayObject:
while( $it->valid() )
{
    echo $it->key() . "=" . $it->current() . "\n";
    $it->next();
}

// The good thing here is that it can be iterated with foreach loop

foreach ($it as $key=>$val)
echo $key.":".$val."\n";

 

Directory Iterator

The directory iterator become important when you need to manipulate directory structure and reading directory files like reading the image files of certain directory and displaying them in a gallery. This approach is much simpler than the classic approach of reading the files using something like fopen or fread.

 

 DirectoryIterator extends SplFileInfo implements SeekableIterator {

   /* snippts */
   public __construct ( string $path )
   public DirectoryIterator current ( void )
   public int getATime ( void )
   public string getBasename ([ string $suffix ] )
   public int getCTime ( void ) 
   public string getExtension ( void )
   public string getFilename ( void )
    public string getPath ( void )
    public string getPathname ( void ) 
    public int getPerms ( void )
    public int getSize ( void )
    public bool isDir ( void )
    
}

As shown the DirectoryIterator support a lot of helper methods for manipulating file structure like retrieving the filename, filesize, filepath, whether it’s a directory or not and many more.

 

In this example we read the contents of the current script directory and display the list of files and their data:

<?php

$objDI = new DirectoryIterator(__DIR__);

print_r($objDI);

echo "<h2>Get Directory path</h2>";

echo $objDI->getPath();

echo "<h2>Get list of files and their sizes in the current directory</h2>";

foreach ($objDI as $fileInfo) {
    if($fileInfo->isFile()) {
        $fileSize = $fileInfo->getSize();
        echo $fileInfo->getFilename().' '.$fileSize." KB<br/>";
    }
}

echo "<h2>Get list of directories in the current directory</h2>";

foreach ($objDI as $fileInfo) {
    if($fileInfo->isDir() && !$fileInfo->isDot()) {
        echo $fileInfo->getFilename()."<br/>";
    }
}


echo "<h2>Get permissions of files in the current directory</h2>";

foreach ($objDI as $fileInfo) {
    if(!$fileInfo->isDot()) {
        $filePerms = substr(sprintf('%o', $fileInfo->getPerms()), -4);
        echo $fileInfo->getFilename() . ' ' . $filePerms."<br/>";
    }
}

echo "<h2>Check if files and directories is writable</h2>";

foreach ($objDI as $fileInfo) {
    if($fileInfo->isWritable()) {
        echo $fileInfo->getFilename() .' is writable<br/>';
    }
}

echo "<h2>Get last access times of files</h2>";

foreach($objDI as $fileinfo) {
    if($fileinfo->isFile()) {
        echo $fileinfo->getFilename() .' '. date("Y-m-d h:i:s", $fileinfo->getATime()) .'<br/>';
    }
}

As shown above we iterate over the directory iterator object and retrieve all of the file data simply by using the directory iterator methods.

 

This function is helpful to retrieve the file data any directory by passing the directory path:

<?PHP
  use \DirectoryIterator;

  function getFileList($dir)
  {
    // array to hold return value
    $retval = [];

    // add trailing slash if missing
    if(substr($dir, -1) != "/") $dir .= "/";

    // open directory for reading
    $d = new DirectoryIterator($dir) or die("getFileList: Failed opening directory $dir for reading");
    foreach($d as $fileinfo) {
      // skip hidden files
      if($fileinfo->isDot()) continue;
      $retval[] = [
        'name' => "{$dir}{$fileinfo}",
        'type' => ($fileinfo->getType() == "dir") ? "dir" : mime_content_type($fileinfo->getRealPath()),
        'size' => $fileinfo->getSize(),
        'lastmod' => $fileinfo->getMTime()
      ];
    }

    return $retval;
  }
?>

To use it like this:

<?PHP
  // examples for scanning the current directory
  $dirlist = getFileList(".");
  $dirlist = getFileList("./");

  // examples for scanning a directory called images
  $dirlist = getFileList("images");

 

Filesystem Iterator

The filesystem iterator much like the directory iterator but the difference is thatDirectoryIterator is an extension of SplFileInfowhileFilesystemIterator is an extension of DirectoryIterator and the both implementsIterator , Traversable , SeekableIterator

 

 FilesystemIterator extends DirectoryIterator implements SeekableIterator {
     /* Some constants */
      const integer CURRENT_AS_PATHNAME = 32 ;
      const integer CURRENT_AS_FILEINFO = 0 ;
      const integer CURRENT_AS_SELF = 16 ;
      const integer CURRENT_MODE_MASK = 240 ;
      const integer KEY_AS_PATHNAME = 0 ;

      /* Some methods */
      public __construct ( string $path [, int $flags = FilesystemIterator::KEY_AS_PATHNAME | FilesystemIterator::CURRENT_AS_FILEINFO | FilesystemIterator::SKIP_DOTS ] )
      public mixed current ( void )
      public int getFlags ( void )
      public string key ( void )
      public void next ( void )
      public void rewind ( void )
      public void setFlags ([ int $flags ] )
}

 

This is an example demonstrate the difference between the DirectoryIterator and the FilesystemIterator

<?php

// directory iterator
$iterator = new DirectoryIterator(dirname(__FILE__));
foreach ( $iterator as $fileinfo ) {
    var_dump($fileinfo->current()); // would return object(DirectoryIterator)
}

<?php

// filesystem iterator
$iterator = new FilesystemIterator(__DIR__, FilesystemIterator::CURRENT_AS_PATHNAME);
foreach ( $iterator as $fileinfo ) {
    var_dump($iterator->current()) . "\n"; // Would return full path eg /www/examples/example.php
}

 

Conclusion

In this tutorial of this series (PHP Iterators) we started talking about the SPL Iterators, and described three of them with examples.

What's your reaction?

Excited
0
Happy
0
Not Sure
0
Confused
0

You may also like

Leave a reply

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