[Перевод] “Yield” и деликатная работа с памятью в PHP

https://pixabay.comhttps://pixabay.com

Вы когда-нибудь задавались вопросом: «Какая польза от yield в PHP?». Позвольте мне избавить вас от поиска в Google; Я с удовольствием раскрою вам пару ключевых моментов о yield:

  1. Что такое yield.

  2. Различия между yield и return.

  3. Варианты использования yield.

  4. Заключение.

  5. Ссылки.

1. Что такое «yield»

Функция-генератор выглядит так же, как и обычная функция, за исключением того, что вместо всего лишь одного значения генератор вырабатывает (yields) столько значений, сколько ему нужно.

Взгляните на следующий пример:

function getValues() {
   yield 'value';
}
// вывод строки "value"
echo getValues();

Конечно, это не будет работать. Предыдущий пример выдаст ошибку: Object of class Generator could not be converted to string. Позвольте мне объяснить почему:

2. Различия между «yield» и «return»

Полученная ошибка говорит нам о том, что функция getValues​​() не возвращает строку, как мы могли бы этого ожидать. Давайте проверим ее тип:

function getValues() {
   return 'value';
}
var_dump(getValues()); // string(5) "value"
function getValues() {
   yield 'value';
}
var_dump(getValues()); // class Gene(0) {}rator#1 

Класс Generator реализует интерфейс Iterator, поэтому для получения значений вам необходимо проитерировать по результатам функции getValue():

foreach (getValues() as $value) {
  echo $value;
}
// можно также сделать это через переменную
$values = getValues();
foreach ($values as $value) {
  echo $value;
}

Но различия на этом не заканчиваются!

Генератор позволяет вам писать код с использованием оператора foreach для итерации по набору данных без необходимости создавать в памяти массив, что, однако, может приводить к превышению лимита памяти.

В следующем примере мы создадим массив из 800000 элементов и вернем его из функции getValues​​(), контролируя память, выделенную для этого фрагмента кода, с помощью функции memory_get_usage (). Мы будем запрашивать потребление памяти через каждые 200000 добавленных элементов, что означает, что контрольных точек будет четыре:

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

0.34 MB
8.35 MB
16.35 MB
32.35 MB

Несколько строк нашего кода потребляют более 30 мегабайт памяти. Каждый раз, когда мы добавляем элемент в массив $valuesArray, мы увеличиваем его размер в памяти.

Давайте рассмотрим тот же пример, только с использованием yield:

Результат для этого варианта кода может вас поразить:

0.34 MB
0.34 MB
0.34 MB
0.34 MB

Конечно это не означает, что вам нужно повсеместно переходить от return к yield, но если в своем приложении вы создаете огромные массивы, которые могут вызывать проблемы с памятью на сервере, yield однозначно будет решением вашей проблемы.

3. Варианты использования «yield»

Существует много вариантов использования yield, но я выделю пару из них:

function getValues() {
  yield 'value';
  return 'returnValue';
}
$values = getValues();
foreach ($values as $value) {}
echo $values->getReturn(); // 'returnValue'
function getValues() {
  yield 'key' => 'value';
}
$values = getValues();
foreach ($values as $key => $value) {
  echo $key . ' => ' . $value;
}

Подробнее об этом можно почитать здесь.

4. Заключение

Основная цель этой статьи — показать на примерах, в чем разница между yield и return в контексте потребления памяти. По моему мнению, это очень важно знать каждому разработчику.

5. Ссылки

  1. http://php.net/manual/en/language.generators.syntax.php

  2. http://php.net/manual/en/class.generator.php

  3. http://php.net/manual/en/language.generators.php

  4. http://php.net/manual/en/function.memory-get-usage.php

Данная статья переведена в преддверии старта курса PHP Developer. Basic. Узнать подробнее о курсе можно по ссылке.

© Habrahabr.ru