Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

reset a pointer for a for-loop in php

Tags:

php

for-loop

given the following code

<?php
$a = array(1,2,3,4,5,6);
$c=0;
foreach($a as $v){
    if($v==5&&$c==0){
        $c=1;
        reset($a);
    }
    var_dump($v);
}

How do I reset the pointer so it will print 1,2,3,4,5,1,2,3,4,5,6 ?

I know that in this case I can simply

<?php
$a = array(1,2,3,4,5,6);
$c=0;
for($i=0;$i<count($a);++$i){
    $v = $a[$i];
    if($v==5&&$c==0){
        $c=1;
        $i=-1;  //because of the loop ++$i
    }
    var_dump($v);
}

But I have a much more complex piece of code and the solution is not as simple as rewrite the loop (not numeric keys).

Any PHP guru out there that can help me here ?

like image 997
Fabrizio Avatar asked Sep 28 '26 09:09

Fabrizio


2 Answers

NOTE: Answer uses function deprecated as of PHP 7.2

As @TheodoreR.Smith pointed out in the comments. list() = each() will not work for any PHP version >= 7.2. See:

How can I update code that uses the deprecated each() function?

Original Answer for version < 7.2

As documented:

Note: When foreach first starts executing, the internal array pointer is automatically reset to the first element of the array. This means that you do not need to call reset() before a foreach loop.

As foreach relies on the internal array pointer, changing it within the loop may lead to unexpected behavior.

http://php.net/manual/en/control-structures.foreach.php

Not sure what "unexpected behavior" is, as I've never tried this...but maybe safer to manually use each()...also more clear in your code.

reset($a);
while(list($key, $val) = each($a)) {
    if($val==5&&$c==0){
        $c=1;
        reset($a);
    }
    var_dump($val);
}

Foreach Issues Explained

I thought I had seen before that you couldn't rely on the internal pointer in the foreach...but couldn't find it in the documentation this time...only "unexpected results". However, thanks to a commenter, I found the text that used to be in the foreach:

Unless the array is referenced, foreach operates on a copy of the specified array and not the array itself. foreach has some side effects on the array pointer. Don't rely on the array pointer during or after the foreach without resetting it."

http://php.net/manual/en/control-structures.foreach.php#114759

like image 117
Kevin Nelson Avatar answered Sep 29 '26 22:09

Kevin Nelson


If you are a fan of OOP, you can use the ArrayIterator class.

It has the method rewind() which is the same as the reset() function.

$a=array(1,2,3,4,5,6);//or $a=range(1,6);

$i=new ArrayIterator($a);

$c=0;

foreach($i as $k=>$v)
{
    if($v==5&&$c==0)
    {
        $c=1;
        $i->rewind();
    }
    var_dump($v);
}

unset($i);//delete the iterator, to free memory

You can test it online on http://writecodeonline.com/php/ or on http://sandbox.onlinephpfunctions.com/

@KevinNelson's answer is the right way to go, but it won't be obvious for the untrained eye.


There's a problem with this code.
Due to the iteration, the number 1 won't be echoed the 2nd time around.

But I've got 2 franken-solutions!

Solution 1: jump over an ignorable element, using the method next()

$a=array(0,1,2,3,4,5,6);//or $a=range(0,6);

$i=new ArrayIterator($a);

$c=0;

$i->next();//jumps over the 1st element

foreach($i as $k=>$v)
{
    if($v==5&&$c==0)
    {
        $c=1;
        $i->rewind();
    }
    var_dump($v);
}

unset($i);

Solution 2: create an element with 'falsy' value (0, null, false, ''...) and ignore it inside the loop

$a=array(0,1,2,3,4,5,6);//or $a=range(0,6);

$i=new ArrayIterator($a);

$c=0;

foreach($i as $k=>$v)
{
    if($v==5&&$c==0)
    {
        $c=1;
        $i->rewind();
    }
    if($v)var_dump($v);
}

unset($i);
like image 37
Ismael Miguel Avatar answered Sep 29 '26 21:09

Ismael Miguel