From: Ryan Panning on 23 Feb 2009 11:31 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 23 Feb 2009 11:44 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 23 Feb 2009 11:53 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 23 Feb 2009 12:25 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 23 Feb 2009 12:27
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. |