[Перевод] “Yield” и деликатная работа с памятью в PHP
https://pixabay.com
Вы когда-нибудь задавались вопросом: «Какая польза от yield в PHP?». Позвольте мне избавить вас от поиска в Google; Я с удовольствием раскрою вам пару ключевых моментов о yield:
Что такое yield.
Различия между yield и return.
Варианты использования yield.
Заключение.
Ссылки.
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. Ссылки
http://php.net/manual/en/language.generators.syntax.php
http://php.net/manual/en/class.generator.php
http://php.net/manual/en/language.generators.php
http://php.net/manual/en/function.memory-get-usage.php
Данная статья переведена в преддверии старта курса PHP Developer. Basic. Узнать подробнее о курсе можно по ссылке.