Как я могу повторить определенную итерацию в цикле foreach в PHP?



Поскольку в PHP нет итератора, единственный способ выполнить цикл через массив без получения длины массива-использовать цикл foreach.



Пусть у меня есть следующий цикл:



foreach ($testing_array as $testing_entry) {
$result = my_testing_api_call($testing_entry);
if ($result == 'server dead')
break;
else if ($result == 'done') {
// do something to handle success code
continue;
}
else {
sleep(5);
// I want to retry my_testing_api_call with current $testing entry, but don't know what to write
}
}


Один из способов сделать это-использовать вместо этого цикл for.



for ( $i=0; $i < count($testing_array); $i++ ) {
$result = my_testing_api_call($testing_entry[$i]);
if ($result == 'server dead')
break;
else if ($result == 'done') {
// do something to handle success code
continue;
}
else {
sleep(5);
$i--; //so it will repeat the current iteration.
}
}


Проблема в том, что $testing_array изначально не использует число в качестве индекса, поэтому мне нужно сделать некоторый массаж данных, чтобы использовать цикл for. Есть ли способ повторить определенную итерацию в цикле foreach?

838   3  

3 ответов:

Возможно, до-пока будет работать для вас.

Непроверенный Код:

foreach ($testing_array as $testing_entry) {
    do {
        $result = my_testing_api_call($testing_entry);
        if ($result == 'server dead') {
            break 2;  // break both loops
        } elseif ($result == 'done') {
            // do something to handle success code
        } else {
            sleep(5);
            // I want to retry my_testing_api_call with current $testing entry, but don't know what to write
        }
    } while ($result !== 'done');
}

Или одна циклическая структура, которая разрушает входной массив при итерации.

Непроверенный Код:

$result = '';
while ($testing_array && $result !== 'server dead') {
    $result = my_testing_api_call(current($testing_array));
    if ($result == 'done') {
        // do something to handle success code
        array_shift($testing_array);
    } elseif ($result !== 'server dead') {
        sleep(5); // I want to retry my_testing_api_call with current $testing entry, but don't know what to write
    }
}

Или вы можете использовать свой цикл for, индексируя $test_array с помощью array_values(), Если вам не нужны ключи в вашем // do something.

$testing_array = array_values($testing_array);
for ($i=0, $count=count($testing_array); $i < $count; ++$i) {
    $result = my_testing_api_call($testing_entry[$i]);
    if ($result == 'server dead') {
        break;
    } else if ($result == 'done') {
        // do something to handle success code
    } else {
        sleep(5);
        --$i; //so it will repeat the current iteration.
    }
}

Если вам нужен сценарий keys down, но вы хотите использовать for, Вы можете хранить индексированный массив ключей, который позволит вам использовать $i для доступа к ключам и поддержания синхронности данных.


Мое последнее предложение:

Используйте while (key($testing_array) !== null) {...} для перемещения указателя без разрушения элементов.

Код: (Демо )

$array1 = [
    "one" => 1,
    "two" => 2,
    "three" => 3,
    "four" => 4
];

while (key($array1)!==null) {  // check if the internal pointer points beyond the end of the elements list or the array is empty
    $current = current($array1);
    $key = key($array1);
    echo "$key => $current\n";         // display current key value pair
    if ($current < 3) {                // an arbitrary condition
        echo "\t";
        $array1[$key] = ++$current;    // increment the current value
    } else {                           // current value is satisfactory
        echo "\t(advance pointer)\n";
        next($array1);                 // move pointer
    }
}

Вывод:

one => 1
    one => 2
    one => 3
    (advance pointer)
two => 2
    two => 3
    (advance pointer)
three => 3
    (advance pointer)
four => 4
    (advance pointer)

Вы пытаетесь обрабатывать две разные вещи в своем цикле, что затрудняет написание чистого потока управления. Вы можете отделить логику повтора от обработки результатов:

function call_api_with_retry($entry) {
  do {
    if (is_defined($result)) sleep(5);
    $result = my_testing_api_call($entry);
  } while ($result != 'done' && $result != 'server dead');
  return $result;
}

foreach ($testing_array as $testing_entry) {
    $result = call_api_with_retry($testing_entry);
    if ($result == 'server dead')
        break;
    else if ($result == 'done') {
        // do something to handle success code
        continue;
    }
}

(там могут быть синтаксические ошибки, прошло некоторое время с тех пор, как я писал PHP-код)

Comments

  1. Удовиченко Юрий
    Удовиченко Юрий 4 года назад
    <p>Просто используйте goto на начало цикла, только обязательно устанавливайте какой-то параметр для выхода из этого цикла пр идостижении какого-то критического количества, иначе получите зависание сервера.</p>