Это сайт — моя персональная записная книжка. Интересна мне, по большей части, история, своя жизнь и немного программирование.

Немаловажное про генераторы в 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);
    }
}
15 комментариев
Аноним 2013

Евгений, часто вижу, что вы пишите слитно «нехватало». Неужели это правильно?

Евгений Степанищев (bolknote.ru) 2013

Комментарий для Аноним:

Нет, разумеется, но я пока не могу побороть в себе эту привычку. Если не успеваю вычитать текст, то моё «нехватало» проскальзывает. Спасибо!

aktuba 2013

Когда программил на Delphi, выработалась привычка: все, что открыто — закрыть в finally. Пройдет время — будет такая привычка и у php-ов)

hshhhhh (hshhhhh.name) 2013

Слушай, я не понимаю зачем эти генераторы нужны. Ну вот честно не понимаю. Как по мне сахар сахаром.
Если бы пхп был асинхронным -​-​ богом дарованная штука, а в синхронном пхп ну зачем они?

Почему их именно «не хватало» если это не более чем сахар.

Евгений Степанищев (bolknote.ru) 2013

Комментарий для hshhhhh.name:

Мне, сове, тяжело в 7 утра придумывать хорошие примеры :) Лучше прочитать статьи про генераторы в Пайтоне, были где-то хорошие. Это другой стиль мышления.

Пока писал это, вспомнил, что у Вани была статья, касающаяся генераторов, которая поможет понять одну из областей где они полезны: http://softwaremaniacs.org/blog/2010/09/18/ijson/

grishaev.me/ 2013

Комментарий для hshhhhh.name:

Главное их преимущество — элементы генератора не хранятся в памяти все разом, как в списке/массиве. Хранится только текущий элемент и состояние генератора для вычисления нового элемента.

hshhhhh (hshhhhh.name) 2013

Комментарий для Евгения Степанищева:

Пока писал это, вспомнил, что у Вани была статья, касающаяся генераторов, которая поможет понять одну из областей где они полезны: http://softwaremaniacs.org/blog/2010/09/18/ijson/

Я, как сова, не очень вник, но потом дочитаю. На первый взгляд я понял что оно возращает key:value из жсона и это круто потому что не жрётся память, но если value будет охеренным объектом -​-​ уже бесполезно.

А делать рекурсивные вхождения -​-​ непонятно как потом обрабатывать.

Я, вроде, понимаю зачем нужны генераторы, но рассматриваю их исключительно как сахар. Хотя надо попробовать поиграться чтоли.

hshhhhh (hshhhhh.name) 2013

Комментарий для http://grishaev.me/:

Главное их преимущество — элементы генератора не хранятся в памяти все разом, как в списке/массиве. Хранится только текущий элемент и состояние генератора для вычисления нового элемента.

ну с ФС проблемы не существует.
с БД не прокатит.
ЖСОН и прочие сериализованные данные, на мой взгляд, универсально парсить не получится.

не понимаю :).

hshhhhh (hshhhhh.name) 2013

Комментарий для Евгения Степанищева:

Я, как сова, не очень вник, но потом дочитаю. На первый взгляд я понял что оно возращает key:value из жсона и это круто потому что не жрётся память, но если value будет охеренным объектом -​-​ уже бесполезно.

Ну тут я оказался неправ, но автор пишет что у него получится приррост по скорости 30%. При этом обрабатывать это неудобно. То есть да, для оптимизации можно пользовать, но лучше хранить код красивым если есть возможность :).

Евгений Степанищев (bolknote.ru) 2013

Комментарий для hshhhhh.name:

Код будет красивым :)

Паша 2013

Давид недавно об этом тоже написал
http://david-m.livejournal.com/1294116.html

Евгений Степанищев (bolknote.ru) 2013

Комментарий для Паша:

Так по моей ссылке он об этом и пишет.

4idroid.com 2013

Комментарий для Евгения Степанищева:

А разве у вас не включено автоматическое исправление ошибок?

4idroid.com 2013

А вообще случайно наткнулся на ваш блог и меня сразу заинтересовал этот пост. Полезная информация, спасибо

Евгений Степанищев (bolknote.ru) 2013

Комментарий для 4idroid.com:

А разве у вас не включено автоматическое исправление ошибок?

Не включено автоматическое исправление ошибок где?