Jonathan Lam
Jonathan Lam

Reputation: 17361

Turn DirectoryIterator into mappable array?

I want to turn the list of directory contents into a JSON array in PHP (I'm very new to PHP). I know this works:

// this code works
$base_dir = './posts/';
$directory_iterator = new Directoryiterator($base_dir);
$file_array = [];
foreach($directory_iterator as $file) {
  if(!$file->isDot()) {
    $file_array[] = $file->getFilename();
  }
}
echo json_encode($file_array);

However, I thought it might be more concise to use aggregate functions (filter and then map) rather than iterating over it. I would imagine it would look something like this in JavaScript:

// this is what I'd imagine it looks like in JS
Array.from(directory_iterator)
  .filter(file => !file.isDot())
  .map(file => file.getFilename())

I tried using iterator_to_array to convert the iterator to an array to perform the aggregate functions on, then use array_filter and array_map, like so:

// this doesn't work
$file_array = array_map(
  function($file) { return $file->getFilename(); },
  array_filter(
    iterator_to_array($directory_iterator),
    function($file) { return !$file->isDot(); })
  );

but the result is:

Array
(
    [0] => 
    [1] => 
    [2] => 
)

When I run var_dump($file->getFilename()) inside the array_filter() callback, it gives me string(0) "". So I'm guessing the original iterator-to-array conversion was wrong.


What am I doing wrong here? Is iterator_to_array() not the correct function to transform the DirectoryIterator object into an array of the file objects within?

Secondly, are there map and filter functions that are methods of the array rather than taking an array as an argument, similar to in JavaScript? I think this would make the code cleaner.

Upvotes: 2

Views: 1798

Answers (3)

Tomasz Kuter
Tomasz Kuter

Reputation: 666

use RecursiveDirectoryIterator;
use SplFileInfo;

class DirectoryContentProvider implements DirectoryContentProviderInterface
{
    /**
     * @param string $path
     *
     * @return SplFileInfo[]
     */
    public function getContent(string $path): array
    {
        $iterator = new RecursiveDirectoryIterator($path);
        $list = iterator_to_array($iterator);

        return array_reduce($list, function (array $carrier, SplFileInfo $file) {
            if ($file->isFile()) {
                $carrier[] = $file;
            }

            return $carrier;
        }, []);
    }
}

Upvotes: 0

sevavietl
sevavietl

Reputation: 3812

If you have nested folders, then you should use RecursiveDirectoryIterator along with RecursiveIteratorIterator. To skip dots use FilesystemIterator::SKIP_DOTS flag. Then you can get paths like following:

$iterator = new RecursiveDirectoryIterator(__DIR__ . '/test/', FilesystemIterator::SKIP_DOTS);
$iterator = new RecursiveIteratorIterator($iterator);

$paths = array_keys(iterator_to_array($iterator));

Iterators are often recursive, so there are no native map and filter functions for them in PHP. To filter an iterator you can use FilterIterator or RecursiveFilterIterator.

Upvotes: 2

evansgambit
evansgambit

Reputation: 915

The iterator_to_array() within the array_filter() function returns an array of DirectoryIterator objects. Then you are running array_map, which is trying to apply a function on each one of the DirectoryIterator object within that array. That's why you are getting an empty list.

Check out the following with 'RecursiveDirectoryIterator'.

// flattens the directory
$it = new RecursiveDirectoryIterator(new DirectoryIterator($dir));

// creates a map - file path as the key and SPLFileInfo as the value
$map = iterator_to_array($it);

// some array functions to use for example;
$filePaths = array_keys($map);

// returns an array of SPLFileInfo objects
$files = array_values($map)

// applies a function on each element in $map - modifies it
array_walk($map, function(&$value, $key) {
    $value = $key . ' => ' . $value->getFilename();
});

// modified
var_dump($map);

You can use the array functions after that. I recommend using built in iterators. Look at the documentation.

Upvotes: 2

Related Questions