tags:

views:

46

answers:

3

I have a foreach loop which loops through an array (simpleXML nodes). This array can have between 0 and several hundred items in it. I'd like to find a way to display the first 10 results and then have a link to display the next 10 and so on.

for instance, I currently have:

$i=0;
$limit=10;
foreach ($nodes as $node){
echo "here is the output: ".$node."<br>\n";
if (++$i >=$limit) break;
}

obviously, no matter how many items are in the $nodes array, it only displays the first 10. But I think I read that foreach loops reset the counter every time they run - so if I wanted to have a link that said: next 10 itmes - I'm not sure how I would tell the the loop to start on index=10.

Am I even barking up the right tree here?

+1  A: 

You should use a regular for loop

if(count($nodes) < 10) {
   $nnodes = count($nodes);
} else {
   $nnodes = 10;
}

for($i = 0; $i < $nnodes; $i++) {
   echo $nodes[$i];
}
Tom Dignan
+2  A: 

This is called pagination. You could extract the segment of the array that you need with array_slice: http://php.net/array_slice

<?php
$page = isset($_GET['page']) ? intval($_GET['page']) : 0;
$elementsPerPage = 10;
$elements = array_slice($nodes, $page * $elementsPerPage, $elementsPerPage);

foreach($elements as $node)
{
    echo "Here is the output: ".$node."<br>\n";
}

Then you only need a link that points to the same page with the argument ?page=$page+1

Sebastian Hoitz
@Sebastian - thanks this works great. I also tried @ircmaxell's solution using Limititerator below which also worked. I wonder if there are any advantages / disadvantages to either one of these solutions?
dijon
+1  A: 

Well, you could use a LimitIterator...

$offset = (int) (isset($_GET['offset']) ? $_GET['offset'] : 0);
$limit = 10;
$arrayIterator = new ArrayIterator($nodes);
$limitIterator = new LimitIterator($arrayIterator, $offset, $limit);

$n = 0;
foreach ($limitIterator as $node) {
    $n++;
    //Display $node;
}
if ($n == 10) {
    echo '<a href="?offset='.($offset + 10).'">Next</a>';
}
ircmaxell
@ircmaxell, Thanks for this - it worked perfectly but I'm wondering about the different approaches taken by you and @Sebastian above. Are there advantages to using Limititerator in this particular case?
dijon
Well, it depends on what you're doing. array_slice will copy the data, so if they are large, it could result in a larger memory footprint. But LimitIterator still iterates over the skipped items (although internally), so there's loss there too. One advantage of LimitIterator is that you can operate on any iterator, not just an array. It's quite powerful. For example, to paginate a list of files in a directory, just create a DirectoryIterator, and pass that to LimitIterator. Iterators are not a trivial concept (which is why more people don't use them) but they are VERY powerful...
ircmaxell
@ircmaxell I'm still new to all those different Iterators introduced by the SPL. I did not know that there is a thing as a LimitIterator. Therefore +1 by me.It would be interesting to see benchmarks for both variants.
Sebastian Hoitz
I'm sure the LimitIterator will likely be slower unless each record is gigantic (since it doesn't need to make a copy). But, it should be more flexible (you can pass it more than just arrays)...
ircmaxell