Немаловажное про генераторы в PHP
Наткнулся на важный пост о генераторах в ПХП, я их попробовал использовать, ещё когда они были в альфе. Хорошая штука, мне после Пайтона их в языке не хватало.
Суть же рассматриваемой проблемы в следующем. Смотрите, вот функция, которая возвращает построчно файл и пример её вызова:
function getLines($file) {
$f = fopen($file, 'r');
while ($line = fgets($f)) {
yield $line;
}
fclose($f);
}
foreach (getLines("file.txt") as $line) {
echo $line;
}
Пока всё чудесно, ничего странного и необычного, а теперь представьте, что нам нужно прочитать только четыре первые строки:
foreach (getLines("file.txt") as $n => $line) {
if ($n > 5) break;
echo $line;
}
Если в файле их было больше, то в функции getLines вызов fclose не выполнится никогда — до него программа просто не дойдёт, файл останется открытым, память занятой и так далее. Плохо. Что делать?
Оказывается, документация обходит этот вопрос стороной, а вот автор введения в ПХП этой конструкции позаботился о том, чтобы эту тему раскрыть — если прочитать соответствующий RFC, становится ясно как быть.
Оказывается, при высвобождении ссылки на генератор, внутри его обязаны выполнится все блоки finally, т. е. вышеприведённый код нужно переписать следующим образом:
function getLines($file) {
$f = fopen($file, 'r');
try {
while ($line = fgets($f)) {
yield $line;
}
} finally {
fclose($f);
}
}
Евгений, часто вижу, что вы пишите слитно «нехватало». Неужели это правильно?
Комментарий для Аноним:
Нет, разумеется, но я пока не могу побороть в себе эту привычку. Если не успеваю вычитать текст, то моё «нехватало» проскальзывает. Спасибо!
Когда программил на Delphi, выработалась привычка: все, что открыто — закрыть в finally. Пройдет время — будет такая привычка и у php-ов)
Слушай, я не понимаю зачем эти генераторы нужны. Ну вот честно не понимаю. Как по мне сахар сахаром.
Если бы пхп был асинхронным -- богом дарованная штука, а в синхронном пхп ну зачем они?
Почему их именно «не хватало» если это не более чем сахар.
Комментарий для hshhhhh.name:
Мне, сове, тяжело в 7 утра придумывать хорошие примеры :) Лучше прочитать статьи про генераторы в Пайтоне, были где-то хорошие. Это другой стиль мышления.
Пока писал это, вспомнил, что у Вани была статья, касающаяся генераторов, которая поможет понять одну из областей где они полезны: http://softwaremaniacs.org/blog/2010/09/18/ijson/
Комментарий для hshhhhh.name:
Главное их преимущество — элементы генератора не хранятся в памяти все разом, как в списке/массиве. Хранится только текущий элемент и состояние генератора для вычисления нового элемента.
Комментарий для Евгения Степанищева:
Я, как сова, не очень вник, но потом дочитаю. На первый взгляд я понял что оно возращает key:value из жсона и это круто потому что не жрётся память, но если value будет охеренным объектом -- уже бесполезно.
А делать рекурсивные вхождения -- непонятно как потом обрабатывать.
Я, вроде, понимаю зачем нужны генераторы, но рассматриваю их исключительно как сахар. Хотя надо попробовать поиграться чтоли.
Комментарий для http://grishaev.me/:
ну с ФС проблемы не существует.
с БД не прокатит.
ЖСОН и прочие сериализованные данные, на мой взгляд, универсально парсить не получится.
не понимаю :).
Комментарий для Евгения Степанищева:
Ну тут я оказался неправ, но автор пишет что у него получится приррост по скорости 30%. При этом обрабатывать это неудобно. То есть да, для оптимизации можно пользовать, но лучше хранить код красивым если есть возможность :).
Комментарий для hshhhhh.name:
Код будет красивым :)
Давид недавно об этом тоже написал
http://david-m.livejournal.com/1294116.html
Комментарий для Паша:
Так по моей ссылке он об этом и пишет.
Комментарий для Евгения Степанищева:
А разве у вас не включено автоматическое исправление ошибок?
А вообще случайно наткнулся на ваш блог и меня сразу заинтересовал этот пост. Полезная информация, спасибо
Комментарий для 4idroid.com:
Не включено автоматическое исправление ошибок где?