Проблемы с PHP DirectoryIterator
В последнее время очень часто приходится сталкиваться с SPL классами в PHP. Не то чтобы они мне не нравились, но работать с ними не всегда удобно. Сегодня наткнулся на проблему с указателями в DirectoryIterator. Ее суть хорошо демонстрирует следующий код.
$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:
$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 набор директорий в виде массива директорий, то буду очень признателен.
-
Не очень красиво смотрится, хотя бы с той точки зрения что постоянно нужно помнить о clone. Зная жизнь, через пару дней, неделю забудится и опять появится эта проблема.
Я бы лучше локально поработал (в цикле foreach). Если необходима только информация о названиях файлов, то кастануть на стринга и в таблице $items держать только стринги (а не инстанции объекта).
Если все же хочется хранить объект, но придется немного доработать класс DirectoryIterator создав например
class My_DirectoryIterator extends DirectoryIterator {
public funciton current() {
//…
}
}здесь уже можно добавить клон. Но опять же, стоит задуматся о том количестве объектов которые могут появится. Если в папке только 5-10 файлов - то нормально, а если их 5-10К или миллионы, то уже такой подход можно смело выбрасить в мусорку.
-
slon, мне тоже как-то не очень нравится использовать clone. Вот пока думаю, как лучше сделать.
Лучшие комментарии
slon
Гость
Не очень красиво смотрится, хотя бы с той точки зрения что постоянно нужно помнить о clone. Зная жизнь, через пару дней, неделю забудится и опять появится эта проблема.
Я бы лучше локально поработал (в цикле foreach). Если необходима только информация о названиях файлов, то кастануть на стринга и в таблице $items держать только стринги (а не инстанции объекта).
Если все же хочется хранить объект, но придется немного доработать класс DirectoryIterator создав например
class My_DirectoryIterator extends DirectoryIterator {
public funciton current() {
//…
}
}
здесь уже можно добавить клон. Но опять же, стоит задуматся о том количестве объектов которые могут появится. Если в папке только 5-10 файлов - то нормально, а если их 5-10К или миллионы, то уже такой подход можно смело выбрасить в мусорку.