Re: [PHP] RecursiveDirectoryIterator and foreach
On Mon, Feb 23, 2009 at 10:27 AM, Ryan Panning wrote: > 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 > > im not sure i fully understand the problem, but from the sound of it, as a work-around, why not something like this, $dirIt = new RecursiveDirectoryIterator($path); foreach($dirIt as $item) { if($item->isDir()) { $subdir = new RecursiveDirectoryIterator($item); // now you have the RecursiveDirectoryIterator you wanted ?? } } -nathan
Re: [PHP] RecursiveDirectoryIterator and foreach
On February 23, 2009 12:32:26 Ryan Panning wrote: > Hi, although I don't think this will work in my situation, there is an > interesting piece of code that you have. > > array_push($this->_dirStack, $this->_curDirIter); > > Are you able to "inject" the iterator with more items? I would like to > do this with the RecursiveDirectoryIterator where-by I "inject" fake > files into the iterator. Is this what you're doing here? Yes, in essence that is what this is doing but I am not manipulating the DirectoryIterator objects. I am instead using my own structure and logic to do this. Basically I'm using normal (i.e flat) DirectoryIterator objects but when I encounter a sub directory, I instantiate another DirectoryIterator for the sub-directory to continue the iteration. In order to remember where I was once I've finished iterating over the sub-directory the current iterator is pushed onto a stack. Then once the iteration of the sub-directory is finished the iterator for the parent directory is popped off the stack and the iteration over that directory continues from where it was interrupted. Does this explanation satisfy your question? -- Philip Graham Lightbox Technologies Suite 312 240 Catherine St. Ottawa, ON, K2P 2G8 613-686-1661 ext. 102 -- PHP General Mailing List (http://www.php.net/) To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP] RecursiveDirectoryIterator and foreach
Philip Graham wrote: Here's a RecursiveDirectoryIterator class I've written and find quite useful: mailto:phi...@lightbox.org";>Philip Graham */ 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! Hi, although I don't think this will work in my situation, there is an interesting piece of code that you have. array_push($this->_dirStack, $this->_curDirIter); Are you able to "inject" the iterator with more items? I would like to do this with the RecursiveDirectoryIterator where-by I "inject" fake files into the iterator. Is this what you're doing here? -- PHP General Mailing List (http://www.php.net/) To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP] RecursiveDirectoryIterator and foreach
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. -- PHP General Mailing List (http://www.php.net/) To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP] RecursiveDirectoryIterator and foreach
On Mon, Feb 23, 2009 at 9:31 AM, 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"; > } 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
Re: [PHP] RecursiveDirectoryIterator and foreach
Here's a RecursiveDirectoryIterator class I've written and find quite useful: mailto:phi...@lightbox.org";>Philip Graham */ 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 -- PHP General Mailing List (http://www.php.net/) To unsubscribe, visit: http://www.php.net/unsub.php
[PHP] RecursiveDirectoryIterator and foreach
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"; } -- PHP General Mailing List (http://www.php.net/) To unsubscribe, visit: http://www.php.net/unsub.php