Генераторы

14 июля 2018
Генератор в PHP это функция, используемая для перебора значений. На каждом вызове функция сохраняет своё состояние, а возврат значения в режиме итераций осуществляется с помощью оператора yield
// Генератор для получения следующих дней
// @param int $count - количество дней
// @return string - строка с датой в формате 'ДД.ММ.ГГГГ' (например, 05.07.2018)
function gen_next_days($count)
{
	if($count<1) yield;  /* Если вызван пустой yield, то функция вернёт NULL */
	$current_timestamp = time();

	for($i=1; $i<=$count; $i++)
	{
		yield date('d.m.Y', $current_timestamp + ($i * 86400));
	}
}

/*
Сегодня 14 июля 2018. 
Следующий код выведет:
15.07.2018
16.07.2018
17.07.2018
*/
$count_days = 3;
foreach(gen_next_days($count_days) as $str_date)
{
	echo $str_date.'<br>';
}

Возврат пары ключ-значение

Для возврата ключа и значения используется конструкция вида yield $key => $value;
function gen_next_days($count)
{
	if($count<1) yield;
	$current_ts = time();

	for($i=1; $i<=$count; $i++)
	{
		$ts = $current_ts + ($i * 86400);
		$str = date('d.m.Y', $ts);
		yield $str => $ts;
	}
}

$count_days = 3;
foreach(gen_next_days($count_days) as $z => $v)
{
	echo $z.' => '.$v.'<br>';
}

Использование return

Если используется оператор yield, то функция будет возвращать объект класса Generator. Начиная с версии PHP 7 генераторы могут возвращать значение через оператор return. Но так как генератор возвращает объект, то получать значения от return нужно с использованием метода getReturn (ссылка на документацию).

Особенности:
  • Оператор return завершит выполнение функции и итераций соответственно;
  • Генератор должен выполнится, иначе при попытке вызова метода getReturn возникнет ошибка Fatal error: Uncaught Exception: Cannot get return value of a generator that hasn't returned
//Генератор обходит числа от 1 до $max
//Функция возвращает число $max
function gen_numbers($max)
{
	for($i=1; $i<=$max; $i++) yield $i;
	return $max;
}

$a = gen_numbers(3);

/*
Если вызвать echo $a->getReturn(), то возникнет ошибка:
Fatal error: Uncaught Exception: Cannot get return value of a generator that hasn't returned
Ошибка возникла из-за того, что итерации генератора не дошли до вызова оператора return
*/

//Запускаем обход генератора
foreach($a as $v) echo $v; /* Выведет 123 */

echo $a->getReturn(); /* Выведет 3 */

Отладка

Для отладки удобно использовать функцию iterator_to_array (ссылка на документацию), которая обходит итерации генератора и возвращает результирующий массив
function gen_next_days($count)
{
	if($count<1) yield;
	$current_ts = time();

	for($i=1; $i<=$count; $i++)
	{
		$ts = $current_ts + ($i * 86400);
		$str = date('d.m.Y', $ts);
		yield $str => $ts;
	}
}

//Заносим результат итераций в массив
$a = iterator_to_array(gen_next_days(3));

echo '<pre>';
print_r($a);
echo '</pre>';

/*
В результате на выводе получим:
Array
(
    [15.07.2018] => 1531602000
    [16.07.2018] => 1531688400
    [17.07.2018] => 1531774800
)