Использование генератора и массива

177
04 декабря 2018, 23:50

Предыстория: я делаю некий обработчик, и на входных данных я получаю обычный массив, следующего формата:

$data = ['guid', 'inp', 'outx', 'dcfoaf'];

(элементы этого массива - скажем так, некие ключи доступа)

Итак, ближе к теме, у меня есть другие данные, которые я обрабатываю через цикл foreach, и, в процессе выполнения этого цикла, у меня есть переменная (к примеру $xkey), в которой случайно выбирается один из ключей массива $data с помощью функции array_rand.

Но я подумал, возможно ли сделать так, чтобы во время обработки моего цикла, с каждой итерацией элемент массива $data выводился по порядку? Например:

  • Первая итерация цикла foreach (в переменной $xkey должно быть значение guid)

  • Вторая итерация цикла foreach (в переменной $xkey должно быть значение inp)

И тому подобное

Но, в чем сложность самого вопроса решения этой задачи, нужно это сделать так, чтобы (когда элементы массива $data заканчиваются) они вызывались в очередной раз сначала. На пятой итерации в переменной $xkey должно быть значение guid, а на шестой inp.

Спустя время, я нашел материал про генераторы в PHP, в котором я увидел оператор yield, там было написано следующее:

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

Я так и не разобрался как можно реализовать решение задачи с помощью этого, прошу помочь с реализацией (на простых примерах тоже приветствуется), и возможна ли она вообще? Жду любой помощи, спасибо!

Answer 1

Достаточно воспользоваться штатным InfiniteIterator, доступным уже очень давно, с PHP 5.1.0

$data = ['guid', 'inp', 'outx', 'dcfoaf'];
// вот и весь фокус:
$infinite = new InfiniteIterator(new ArrayIterator($data));
$i = 0;
foreach ($infinite as $xkey) {
    echo '$xkey = '.$xkey.PHP_EOL;
    if (++$i > 30) break; // чтобы хоть когда-нибудь прерваться
}

Можно и через генератором воспользоваться:

$data = ['guid', 'inp', 'outx', 'dcfoaf'];
$infinite = function($input) {
    while (true) {
        yield from $input;
    }
};
$i = 0;
foreach ($infinite($data) as $xkey) {
    echo '$xkey = '.$xkey.PHP_EOL;
    if (++$i > 30) break;
}

А в принципе и PHP4 достаточно с указателем на элемент массива:

$data = ['guid', 'inp', 'outx', 'dcfoaf'];
$i = 0;
$xkey = current($data); // получаем первый элемент
while (true) {
    echo '$xkey = '.$xkey.PHP_EOL;
    if (++$i > 30) break;
    $xkey = next($data);
    if ($xkey === false) {
        // следующего нет, берём вновь начало
        $xkey = reset($data);
    }
}
Answer 2

как еще один вариант решения без итераторов, уже упомянутый мною в комментарии, но обернутый в желаемую форму последовательного вызова функций:

$data = ['guid', 'inp', 'outx', 'dcfoaf'];
function demark(){
    static $i = 0;
    global $data;
    return $data[ $i++ % count($data)];
}
echo demark();
echo demark();
echo demark();
echo demark();
echo demark();
echo demark();
echo demark();
READ ALSO
laravel redirect на post запрос

laravel redirect на post запрос

Пишу api для своего мобильного приложения на laravelПри отправках пост запроса из приложения сервер отвечает редиректом(301) на этот же url, но по GET

153
Laravel Eloquent ORM можно ли сохранять через связи

Laravel Eloquent ORM можно ли сохранять через связи

Допустим у меня есть две модели: User и Friend

188
Проверить есть ли в строке кириллица

Проверить есть ли в строке кириллица

Есть код, который переводит верхний регистр в нижний

249
Конвертация *.raw с камеры GitUp G3 в *.tiff

Конвертация *.raw с камеры GitUp G3 в *.tiff

Всем приветВозникла такая проблема

197