user3307827
user3307827

Reputation: 556

how to force foreach reset in php

Is possible in php to reset The foreach?

for example:

foreach($rows as $row)
{
  if(something true)
  {
     continue foreach;
  }
  else
  {
     break;
     reset foreach;//I mean start foreach again...
  }
}

----------------------------------Edited

Thanks my friend for your answers...

The condition generate from result of foreach so I can not use function. I wana sortet it by (fro example) alphabet...in many DIV html. I can not filter result by SQL for same reson.

So mybe I have to use a css trick.

Upvotes: 7

Views: 16185

Answers (7)

Dealazer
Dealazer

Reputation: 69

You can reset the foreach with: "using it in this below as well"

$value = "";

Or restart by pointing where to go after the end:

a:
"as restarting"
goto a;

So in the code from the asker in this post do like this:

a:
foreach($rows as $row){
  $value++;
  if(something true){
  continue foreach;
  }
  else {
  break;
  $value = ""; // A value reset
  goto a; //I mean start foreach again...
  } 
$value = ""; //perhaps a value reset here?
}

Upvotes: 0

Ultimater
Ultimater

Reputation: 4738

Try using reset/while/each which is functionally equivalent to foreach according to the manual then you can use reset within the loop like so:

<?php
$arr = array(1=>'one',2=>'two',3=>'three');
reset($arr);
$resets=0;
while (list($key, $value) = each($arr))
{
    echo "$key => $value<br />\n";
    if($value=='three')
    {
        if($resets==0){$resets++;echo "==Resetting==<br />\n";reset($arr);continue;}
    }

}

Output:

1 => one
2 => two
3 => three
==Resetting==
1 => one
2 => two
3 => three

As pointed out by Mike Kormendy in the comments, each is deprecated as of php 7.2.

If for some reason you like my approach, you can emulate each using a combination of key(), current(), and next() like so:

<?php
$arr = array(1=>'one',2=>'two',3=>'three');
reset($arr);
$resets=0;
while ( list($key,$value) = [key($arr),current($arr)] )
{
    if($key === NULL){ break; }
    next($arr);

    echo "$key => $value<br />\n";
    if($value=='three')
    {
        if($resets==0){$resets++;echo "==Resetting==<br />\n";reset($arr);continue;}
    }
}

Output:

1 => one
2 => two
3 => three
==Resetting==
1 => one
2 => two
3 => three

This answer was posted many years ago.
Going forward, I'd avoid this type of approach like the plague.

The accepted answer is a lot more elegant.

Upvotes: 2

Julian
Julian

Reputation: 4666

Yes it is possible to reset a foreach but not the way you described it in your question. You can read my approaches below.

--------- Implement Iterator --------------------------------

Implement the Iterator interface.

Link: https://www.php.net/manual/en/class.iterator.php.

Code example:

class myIterator implements Iterator {

    private $maxIterations = 2; // the maxumum amount of iterations
    private $currentIteration = 1; // the current iteration number

    private $lastKey = null;
    private $lastValue = null;
    private $currentValue = null;

    private $position = 0;

    private $array;


    public function __construct($array) {
        $this->array = $array;
        end($array);
        $this->lastKey = key($array);
        $this->lastValue = current($array);
    }

    public function rewind() {
        $this->position = 0;
        reset($this->array);
    }

    public function valid() { 
        // Reset when there are no elements
        if($this->position > $this->lastKey && 
           $this->currentValue === $this->lastValue &&           
           $this->currentIteration < $this->maxIterations){

           $this->rewind();
           ++$this->currentIteration;
        }
        $isSet = isset($this->array[$this->position]);
        return $isSet;
    }

    public function current() {
        $this->currentValue = $this->array[$this->position];
        return $this->currentValue;
    }

    public function key() {
        return $this->position;
    }

    public function next() {
        ++$this->position;
    }
}

$array = array("A",
      "B",
      "C",
);
$it = new myIterator($array);

// the iterator will traverse the array twice
foreach($it as $key => $value) {
    echo 'key : ' . $key . '<br>';
    echo 'val : ' . $value . '<br>';
    echo '<br>';
}

The output

key : 0
val : A

key : 1
val : B

key : 2
val : C

key : 0
val : A

key : 1
val : B

key : 2
val : C

--------- InfiniteIterator + LimitIterator --------------------------------

You can use InfiniteIterator in combination with LimitIterator.

$obj = new stdClass();
$obj->Mon = "Monday";
$obj->Tue = "Tuesday";
$obj->Wed = "Wednesday";
$obj->Thu = "Thursday";
$obj->Fri = "Friday";
$obj->Sat = "Saturday";
$obj->Sun = "Sunday";

$infinate = new InfiniteIterator(new ArrayIterator($obj));
foreach ( new LimitIterator($infinate, 0, 14) as $value ) {
    print($value . PHP_EOL);
}

// OUTPUT: 
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday

See link: http://php.net/manual/en/class.infiniteiterator.php

--------- ArrayObject + ArrayIterator --------------------------------

According to the PHP manual it should also be possible to achieve it by using ArrayIterator.

When you want to iterate over the same array multiple times you need to instantiate ArrayObject and let it create ArrayIterator instances that refer to it either by using foreach or by calling its getIterator() method manually.

Their description is not clear to me, but it think that they mean something like this.

$array = array('honda', 'toyota', 'suzuki', 'mazda', 'nissan');

end($array);
$lastKey = key($array);
$maxIterations = 2;
$currentIteration = 1;
$arrayObj = new ArrayObject($array);
for($iterator = $arrayObj->getIterator(); $iterator->valid(); $iterator->next()){

    echo $iterator->key() . ' : ' . $iterator->current() . '<br>';

    if( $iterator->key() === $lastKey &&
        $currentIteration < $maxIterations ){

        $iterator->rewind();
        ++$currentIteration;

        echo $iterator->key() . ' : ' . $iterator->current() . '<br>';
    }
}

OUTPUT:

0 : honda
1 : toyota
2 : suzuki
3 : mazda
4 : nissan
0 : honda
1 : toyota
2 : suzuki
3 : mazda
4 : nissan

Link: http://php.net/manual/en/class.arrayiterator.php

Upvotes: 0

smassey
smassey

Reputation: 5931

You could do something around these lines (and avoid the limitations of recursion):

while (True) {
    $reset = False;
    foreach ($rows as $row) {
      if(something true) {
         continue;
      } else {
          $reset = True;
          break;
      }
    }
    if ( ! $reset ) {
        break; # break out of the while(true)
    }
    # otherwise the foreach loop is `reset`
}

Upvotes: 9

Azrael_404
Azrael_404

Reputation: 446

Why reset the foreach ? If you really need this... But care about infinite loop !

function myForeach($array){
    foreachforeach($rows as $row){
        if(something true){
           continue foreach;
        }else{
           myForeach($array);
        }

Upvotes: 1

magnetronnie
magnetronnie

Reputation: 505

I think you can do that by putting the for each in a function and then calling the function from itself.

function doForEach($rows) {
    foreach($rows as $row)
    {
        if(something true)
        {
            continue foreach;
        }
        else
        {
            break;
            doForEach($rows);
        }
    }
}

Be very careful with this however, you'll likely end up in a loop.

Upvotes: 1

Halcyon
Halcyon

Reputation: 57709

It seems that reset inside a foreach has no effect.

You can implement this if you make your own Traversable.

Upvotes: 3

Related Questions