// codeart.ru / Главная / Проблемы с PHP DirectoryIterator

Проблемы с PHP DirectoryIterator

Автор: Evgeny Sergeev

В последнее время очень часто приходится сталкиваться с SPL классами в PHP. Не то чтобы они мне не нравились, но работать с ними не всегда удобно. Сегодня наткнулся на проблему с указателями в DirectoryIterator. Ее суть хорошо демонстрирует следующий код.

$dirTree = new DirectoryIterator("/testDir"); // Допустим в директории файлы a.php и b.php
$items = array();                                                                                                                                                               
foreach($dirTree as $item) {                                                                                                                                                   
   if ($item->isDir()) {                                                                                                                                                     
         $items[]$item;                                                                                                                                                   
         echo $item->getFilename(); // Здесь все ок - сначало выводится a.php, затем b.php
   }                                                                                                                                                                         
}                                                                                                                                                                               

$firstElement = $items[0];                                                                                                                                                     
var_dump($firstElement->getFilename()); // вот здесь выводится пустая строка, а я ожидал что будет ‘a.php’

Проблема заключается в том, что при выполнении foreach у нас в элементе $item хранится указатель на указатель текущего элемента в DirectoryIterator. Получить этот указатель можно с помощью функции $dirTree->current(). Таким образом, при изменении этого самого внутреннего указателя изменяется и результат выполнения команды getFilename. А так как после выполнения Foreach указатель смотрит на несуществующий (null) элемент итератора, то getFilename возвращает пустое значение.

Пока я ничего лучше не придумал, чем копировать $item с помощью метода clone:

$dirTree = new DirectoryIterator("/testDir"); // Допустим в директории файлы a.php и b.php
$items = array();                                                                                                                                                               
foreach($dirTree as $item) {                                                                                                                                                   
   if ($item->isDir()) {                                                                                                                                                     
         $items[] = clone $item;                                                                                                                                                   
         echo $item->getFilename(); // Здесь все ок - сначало выводится a.php, затем b.php
   }                                                                                                                                                                         
}                                                                                                                                                                               

$firstElement = $items[0];                                                                                                                                                     
var_dump($firstElement->getFilename()); // теперь тоже все ок и на экран выводитя - ‘a.php’

Решение мне кажется не очень изящным, поэтому если кто-то подскажет действительно красивый способ выдернуть из DirectoryIterator набор директорий в виде массива директорий, то буду очень признателен.

    Лучшие комментарии

  1. Не очень красиво смотрится, хотя бы с той точки зрения что постоянно нужно помнить о clone. Зная жизнь, через пару дней, неделю забудится и опять появится эта проблема.

    Я бы лучше локально поработал (в цикле foreach). Если необходима только информация о названиях файлов, то кастануть на стринга и в таблице $items держать только стринги (а не инстанции объекта).

    Если все же хочется хранить объект, но придется немного доработать класс DirectoryIterator создав например
    class My_DirectoryIterator extends DirectoryIterator {
    public funciton current() {
    //…
    }
    }

    здесь уже можно добавить клон. Но опять же, стоит задуматся о том количестве объектов которые могут появится. Если в папке только 5-10 файлов - то нормально, а если их 5-10К или миллионы, то уже такой подход можно смело выбрасить в мусорку.

  1. Не очень красиво смотрится, хотя бы с той точки зрения что постоянно нужно помнить о clone. Зная жизнь, через пару дней, неделю забудится и опять появится эта проблема.

    Я бы лучше локально поработал (в цикле foreach). Если необходима только информация о названиях файлов, то кастануть на стринга и в таблице $items держать только стринги (а не инстанции объекта).

    Если все же хочется хранить объект, но придется немного доработать класс DirectoryIterator создав например
    class My_DirectoryIterator extends DirectoryIterator {
    public funciton current() {
    //…
    }
    }

    здесь уже можно добавить клон. Но опять же, стоит задуматся о том количестве объектов которые могут появится. Если в папке только 5-10 файлов - то нормально, а если их 5-10К или миллионы, то уже такой подход можно смело выбрасить в мусорку.

  2. slon, мне тоже как-то не очень нравится использовать clone. Вот пока думаю, как лучше сделать.

Leave a Reply

« Как быстро проверить число на NaN Подсмотрел интересный прием в ExtJs »