From: Ryan Panning on
I have discovered that when I foreach over a RecursiveDirectoryIterator
(see example below) the $item actually turns into a SplFileInfo object.
I would expect it to be a RecursiveDirectoryIterator. How do I do a
hasChildren() on SplFileInfo?

However, if I change it to a non-recursive, DirectoryIterator, $item is
what I would expect, DirectoryIterator. I've tested this with 5.2.8 and
5.3b1. I'm guessing this is an issue with my setup as I'm sure I've
gotten this to work before...


$dir = new RecursiveDirectoryIterator('/path/to/dir');
foreach ($dir as $item) {
print get_class($item) . "\r\n";
}
From: Philip Graham on
Here's a RecursiveDirectoryIterator class I've written and find quite useful:

<?php
/**
* This class encapsulates an iterator that iterates over all the files in a
* directory recursively. Only files that don't begin with a '.' are included
* in this iteration. This class essentially wraps an SPL DirectoryIterator
* object and returns each file in the iteration as an SplFileInfo.
*
* @author <a href="mailto:philip(a)lightbox.org">Philip Graham</a>
*/
class Util_RecursiveFileIterator implements Iterator {
CONST SHOW_DOT_FILES = true;

private $_basePath;
private $_curDirIter;
private $_dirStack;
private $_showDots;

/**
* Constructor. By default the iteration will skip any files that begin
* with a '.' character but this can be changed by passing the class
* constant SHOW_DOT_FILES as the second parameter.
*
* @param string $basePath - The base path of the directory to iterate
over
* @param boolean $showDots - Whether or not to include files that begin
* with a '.' character in the iteration.
*/
public function __construct($basePath, $showDots = false) {
// PREPARE ... THE ... HUMANOID
if(!is_dir($basePath)) {
$basePath = dirname($basePath);
}
if(!$basePath) {
$basePath = '.';
}
// If the given path is relative this function will transform it
// into an equivalent path. This call assumes that the relative path
// is relative to the file that created this iterator.
$this->_basePath = Util_File::getAbsolutePath($basePath, 2);

$this->_showDots = $showDots;

}

/**
* Returns the current value of the iteration
*
* @return FileInfoInfo
*/
public function current() {
return $this->_curDirIter->current();
}

/**
* Returns the index of the current entry.
*
* @return string
*/
public function key() {
$curPath = $this->_curDirIter->getPathname();
$relativeToBase = substr($curPath, strlen($this->_basePath));
return $relativeToBase;
}

/**
* Moves the directory iterator to the next element of the iteration.
*/
public function next() {
$this->_curDirIter->next();
$good = false;
while(!$good) {
if(!$this->_curDirIter->valid()) {
if(count($this->_dirStack) == 0) {
$good = true;
} else {
$this->_curDirIter = array_pop($this->_dirStack);
}
} else if($this->_curDirIter->isDot()) {
if(!$this->_showDots) {
$this->_curDirIter->next();
} else {
$good = true;
}
} else if(!$this->_showDots &&
substr($this->_curDirIter->getFileName(), 0, 1) == '.') {
$this->_curDirIter->next();
} else if($this->_curDirIter->isDir()) {
// Create a new iterator for the sub-dir
$newIter = new DirectoryIterator(
$this->_curDirIter->getPathname());

// Make sure the current iterator is ready to go when it
// gets popped off the stack
$this->_curDirIter->next();

// Push it... push it real good
array_push($this->_dirStack, $this->_curDirIter);

// Set the new iterator
$this->_curDirIter = $newIter;
} else {
$good = true;
}
}
}

/**
* Resets the iterator to first file in the object's base path.
*/
public function rewind() {
$this->_curDirIter = new DirectoryIterator($this->_basePath);
$this->_dirStack = array();
if(!$this->_showDots && $this->_curDirIter->isDot()) {
$this->next();
}
}

/**
* Returns a boolean indicating wether or not there are anymore elements
left
* in the iteration.
*/
public function valid() {
return $this->_curDirIter->valid();
}
}

Usage:

$dirIter = new Util_RecursiveFileIterator('/path/to/directory');
foreach($dirIter AS $fileName => $fileInfo) {
// $fileName is the basename of the file and $fileInfo is a SplFileInfo
// for the file
}

Hope this helps!


On February 23, 2009 11:31:04 Ryan Panning wrote:
> I have discovered that when I foreach over a RecursiveDirectoryIterator
> (see example below) the $item actually turns into a SplFileInfo object.
> I would expect it to be a RecursiveDirectoryIterator. How do I do a
> hasChildren() on SplFileInfo?
>
> However, if I change it to a non-recursive, DirectoryIterator, $item is
> what I would expect, DirectoryIterator. I've tested this with 5.2.8 and
> 5.3b1. I'm guessing this is an issue with my setup as I'm sure I've
> gotten this to work before...
>
>
> $dir = new RecursiveDirectoryIterator('/path/to/dir');
> foreach ($dir as $item) {
> print get_class($item) . "\r\n";
> }
--
Philip Graham
Lightbox Technologies
Suite 312 240 Catherine St.
Ottawa, ON, K2P 2G8
613-686-1661 ext. 102
From: Nathan Nobbe on
On Mon, Feb 23, 2009 at 9:31 AM, Ryan Panning <rpanning(a)gmail.com> wrote:

> I have discovered that when I foreach over a RecursiveDirectoryIterator
> (see example below) the $item actually turns into a SplFileInfo object. I
> would expect it to be a RecursiveDirectoryIterator. How do I do a
> hasChildren() on SplFileInfo?
>
> However, if I change it to a non-recursive, DirectoryIterator, $item is
> what I would expect, DirectoryIterator. I've tested this with 5.2.8 and
> 5.3b1. I'm guessing this is an issue with my setup as I'm sure I've gotten
> this to work before...
>
>
> $dir = new RecursiveDirectoryIterator('/path/to/dir');
> foreach ($dir as $item) {
> print get_class($item) . "\r\n";
> }


if youre trying to do recursive iteration whereby you 'flatten' the tree
structure, drop the RecursiveDirectoryIterator into a
RecursiveIteratorIterator (its for iterating over RecursiveIterators), then
you dont have to bother w/ calling hasChildren() at all. you probly also
want to look at the constructor args, since by default, it only returns leaf
nodes.

$dir = new RecursiveDirectoryIterator('/path/to/dir');

$itt = new RecursiveIteratorIterator($dir,
RecursiveIteratorIterator::CHILD_FIRST);

> foreach ($itt as $item) {
> print get_class($item) . "\r\n";
> }


-nathan
From: Ryan Panning on
Ryan Panning wrote:
> I have discovered that when I foreach over a RecursiveDirectoryIterator
> (see example below) the $item actually turns into a SplFileInfo object.
> I would expect it to be a RecursiveDirectoryIterator. How do I do a
> hasChildren() on SplFileInfo?
>
> However, if I change it to a non-recursive, DirectoryIterator, $item is
> what I would expect, DirectoryIterator. I've tested this with 5.2.8 and
> 5.3b1. I'm guessing this is an issue with my setup as I'm sure I've
> gotten this to work before...
>
>
> $dir = new RecursiveDirectoryIterator('/path/to/dir');
> foreach ($dir as $item) {
> print get_class($item) . "\r\n";
> }

Alright, I've found a related PHP bug report.
http://bugs.php.net/bug.php?id=44018

It seems that the default behavior is to return a SplFileInfo object.
However, if 0 is passed as a flag then a RecursiveDirectoryIterator
should be returned. However, I cannot seem to get that to work with
5.2.8. Testing previous versions, this option no longer works as of
5.2.6, but did in 5.2.5.

This seems like a bug to me, however that bug was marked as "Wont Fix".
The default behavior should be RecursiveDirectoryIterator as there is a
flag for CURRENT_AS_FILEINFO. Any thoughts on that?

@ Marcus, what was the reasoning not to fix this? And why did it break
in 5.2.6?

In relation, I've found a workaround, use while(). That way I'm always
working off of the $dir. I'd rather use foreach though..


$dir = new RecursiveDirectoryIterator('/path/to/dir');
while ($dir->valid()) {
print get_class($dir) . "\r\n";
$dir->next();
}
From: Ryan Panning on
Nathan Nobbe wrote:
> if youre trying to do recursive iteration whereby you 'flatten' the tree
> structure, drop the RecursiveDirectoryIterator into a
> RecursiveIteratorIterator (its for iterating over RecursiveIterators), then
> you dont have to bother w/ calling hasChildren() at all. you probly also
> want to look at the constructor args, since by default, it only returns leaf
> nodes.
>
> $dir = new RecursiveDirectoryIterator('/path/to/dir');
>
> $itt = new RecursiveIteratorIterator($dir,
> RecursiveIteratorIterator::CHILD_FIRST);
>
>> foreach ($itt as $item) {
>> print get_class($item) . "\r\n";
>> }
>
>
> -nathan
>

Hi, thanks for the idea. In my case I do not want to flatten the tree.
When there is a sub-directory I make a repeat call to the
function/method, there-by calling it for each directory. I'd give you
more details but I don't think it'd help with this specific issue.