将DirectoryIterator转换为可映射数组?

时间:2018-06-12 01:37:21

标签: php arrays iterator

我想将目录内容列表转换为PHP中的JSON数组(我是PHP的新手)。我知道这有效:

// 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);

但是,我认为使用聚合函数(过滤器然后映射)而不是迭代它可能更简洁。我想在JavaScript中会看起来像这样:

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

我尝试使用iterator_to_array将迭代器转换为数组以执行聚合函数,然后使用array_filterarray_map,如下所示:

// 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(); })
  );

但结果是:

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

当我在var_dump($file->getFilename())回调中运行array_filter()时,它会给我string(0) ""。所以我猜测原始迭代器到数组的转换是错误的。

我在这里做错了什么? iterator_to_array()不是将DirectoryIterator对象转换为文件对象数组的正确函数吗?

其次,是否存在作为数组方法的map和filter函数,而不是将数组作为参数,类似于JavaScript?我认为这会使代码更清晰。

3 个答案:

答案 0 :(得分:2)

array_filter()函数中的iterator_to_array()返回一个DirectoryIterator对象数组。然后你运行的是array_map,它试图在该数组中的每个DirectoryIterator对象上应用一个函数。这就是为什么你得到一个空列表。

使用' 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);

之后您可以使用数组函数。我建议使用内置iterators。查看文档。

答案 1 :(得分:1)

如果您有嵌套文件夹,则应使用RecursiveDirectoryIteratorRecursiveIteratorIterator。要跳过点,请使用FilesystemIterator::SKIP_DOTS标记。然后你可以获得如下路径:

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

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

迭代器通常是递归的,因此PHP中没有本地mapfilter函数。要过滤迭代器,您可以使用FilterIteratorRecursiveFilterIterator

答案 2 :(得分:0)

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;
        }, []);
    }
}