Reputation: 17361
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
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
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
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