Doc #62914 [Asn]: First entry appears twice, unless rewind method is called first

From: Date: Fri, 28 Mar 2014 19:39:07 +0000
Subject: Doc #62914 [Asn]: First entry appears twice, unless rewind method is called first
References: 1  Groups: php.doc.bugs 
Request: Send a blank email to doc-bugs+get-11100@lists.php.net to get a copy of this message
Edit report at https://bugs.php.net/bug.php?id=62914&edit=1 ID: 62914 Updated by: levim@php.net Reported by: lveyde at gmail dot com Summary: First entry appears twice, unless rewind method is called first Status: Assigned Type: Documentation Problem Package: SPL related Operating System: CentOS 6.3 PHP Version: 5.3.16 -Assigned To: salathe +Assigned To: levim Block user comment: N Private report: N New Comment: Iterators must be rewound before being used. The documentation is in error here, even if something works without being rewound in certain PHP versions. I'll update the documentation, then mark this as closed. Previous Comments: ------------------------------------------------------------------------ [2013-11-20 11:44:37] duke at ejoom dot com Small script to reproduce bug: <?php $arr = array('first', 'second' => array('subsecond')); $it = new \RecursiveIteratorIterator(new \RecursiveArrayIterator($arr)); var_dump($it->current()); $it->next(); var_dump($it->current()); $it->rewind(); var_dump($it->current()); $it->next(); var_dump($it->current()); ?> results: string 'first' (length=5) string 'first' (length=5) string 'first' (length=5) string 'subsecond' (length=9) expects: string 'first' (length=5) string 'subsecond' (length=9) string 'first' (length=5) string 'subsecond' (length=9) PHP 5.5.5, Ubuntu. ------------------------------------------------------------------------ [2012-09-13 05:14:12] googleguy@php.net You stated you're using PHP version 5.3.3 in your bug description, but your bug report says 5.3.16. I can not reproduce this behavior in PHP 5.3.16, however I have found that it is evident in early version of 5.3, prior to 5.3.10. Steps to reproduce: 1) Create a temporary directory somewhere and your file system and create some empty files in that directory for testing. cd /tmp mkdir test touch test1 & touch test2 & touch test3 2) Run the following PHP script <?php $directory = "/tmp/test"; $it = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($directory)); while ($it->valid()) { if (!$it->isDot()) var_dump($it->key()); $it->next(); } ?> Here's the output I got in PHP 5.3.2 (order is not important here): string(15) "/tmp/test/test3" string(15) "/tmp/test/test3" string(15) "/tmp/test/test1" string(15) "/tmp/test/test2" --------------------------------- Here's the output I got in 5.3.10 all the way to the latest 5.4 string(15) "/tmp/test/test2" string(15) "/tmp/test/test3" string(15) "/tmp/test/test1" ------------------------------ The only potential documentation bug here is that the changelog doesn't reflect any changes in the behavior of RecursiveDirectoryIterator that would indicate why this bug existed. I haven't been able to find any bug reports on the issue, but obviously it was a problem at some point. I'll see if we need to update the changelog about this behavior and if necessary will open a bug report for SPL. ------------------------------------------------------------------------ [2012-08-26 14:52:19] phpbugs at jessemccarthy dot net I'm running into this too, in PHP 5.3.6 (Apache module / CLI) on Ubuntu 11.10. Test case directory structure: test/ a/ b.php iterate.php while.php foreach.php rewind-while.php iterator_to_array.php iterate.php is used in all of the other scripts: <?php header( "Content-Type: text/plain" ); $it = new RecursiveIteratorIterator( new RecursiveDirectoryIterator( __DIR__ . "/a", FilesystemIterator::SKIP_DOTS ), RecursiveIteratorIterator::CHILD_FIRST ); function show_items( $items ) { var_dump( $items ); } $items = array(); **************************************** Expected result from all scripts: **************************************** array(1) { [0]=> string(5) "b.php" } Content of the test scripts and actual results: **************************************** while.php **************************************** <?php require_once "iterate.php"; while ( $it->valid() ) { $items[] = $it->getFilename(); $it->next(); } show_items( $items ); ======================================== array(2) { [0]=> string(5) "b.php" [1]=> string(5) "b.php" } **************************************** foreach.php **************************************** <?php require_once "iterate.php"; foreach ( $it as $file ) { $items[] = $file->getFilename(); } show_items( $items ); ======================================== array(1) { [0]=> string(5) "b.php" } **************************************** rewind-while.php **************************************** <?php require_once "iterate.php"; $it->rewind(); require_once "while.php"; ======================================== array(1) { [0]=> string(5) "b.php" } **************************************** iterator_to_array.php **************************************** <?php require_once "iterate.php"; $items = array_map( function ( $item ) { return $item->getFilename(); }, array_values( iterator_to_array( $it ) ) ); show_items( $items ); ======================================== array(1) { [0]=> string(5) "b.php" } As you can see, iterating with while and next() produces an unexpected duplicate value, whereas foreach, iterator_to_array(), and the rewind() then while suggested by the OP produce the expected result. ------------------------------------------------------------------------ [2012-08-23 22:18:04] lveyde at gmail dot com Description: ------------ --- From manual page: http://www.php.net/recursivedirectoryiterator.construct --- I tried to run the sample code (changing the directory), and unless the call to the rewind() method is performed before using the iterator, the first entry appears twice in the output. I'm using PHP version 5.3.3, the latest available with RHEL/CentOS 6.x. <?php $directory = '/root/isos'; $it = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($directory)); // Added this $it->rewind(); while($it->valid()) { if (!$it->isDot()) { echo 'SubPathName: ' . $it->getSubPathName() . "\n"; echo 'SubPath: ' . $it->getSubPath() . "\n"; echo 'Key: ' . $it->key() . "\n\n"; } $it->next(); } ?> Is that a normal behavior (and thus bug in the documentation) ? Test script: --------------- <?php $directory = '/root/isos'; $it = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($directory)); while($it->valid()) { if (!$it->isDot()) { echo 'SubPathName: ' . $it->getSubPathName() . "\n"; echo 'SubPath: ' . $it->getSubPath() . "\n"; echo 'Key: ' . $it->key() . "\n\n"; } $it->next(); } ?> Expected result: ---------------- SubPathName: CentOS-6.2-x86_64-netinstall.iso SubPath: Key: /root/isos/CentOS-6.2-x86_64-netinstall.iso SubPathName: CentOS-6.2-x86_64-bin-DVD1.iso SubPath: Key: /root/isos/CentOS-6.2-x86_64-bin-DVD1.iso SubPathName: CentOS-6.2-x86_64-LiveCD.iso SubPath: Key: /root/isos/CentOS-6.2-x86_64-LiveCD.iso SubPathName: CentOS-6.2-x86_64-bin-DVD2.iso SubPath: Key: /root/isos/CentOS-6.2-x86_64-bin-DVD2.iso Actual result: -------------- SubPathName: CentOS-6.2-x86_64-netinstall.iso SubPath: Key: /root/isos/CentOS-6.2-x86_64-netinstall.iso SubPathName: CentOS-6.2-x86_64-netinstall.iso SubPath: Key: /root/isos/CentOS-6.2-x86_64-netinstall.iso SubPathName: CentOS-6.2-x86_64-bin-DVD1.iso SubPath: Key: /root/isos/CentOS-6.2-x86_64-bin-DVD1.iso SubPathName: CentOS-6.2-x86_64-LiveCD.iso SubPath: Key: /root/isos/CentOS-6.2-x86_64-LiveCD.iso SubPathName: CentOS-6.2-x86_64-bin-DVD2.iso SubPath: Key: /root/isos/CentOS-6.2-x86_64-bin-DVD2.iso ------------------------------------------------------------------------ -- Edit this bug report at https://bugs.php.net/bug.php?id=62914&edit=1

« previous php.doc.bugs (#11100) next »