Bug #71980 [Ver->Csd]: Decorated/Nested Generator is Uncloseable in Finally

From: Date: Thu, 07 Apr 2016 10:30:58 +0000
Subject: Bug #71980 [Ver->Csd]: Decorated/Nested Generator is Uncloseable in Finally
References: 1  Groups: php.bugs 
Request: Send a blank email to php-bugs+get-200383@lists.php.net to get a copy of this message
Edit report at https://bugs.php.net/bug.php?id=71980&edit=1 ID: 71980 Updated by: nikic@php.net Reported by: php at fleshgrinder dot com Summary: Decorated/Nested Generator is Uncloseable in Finally -Status: Verified +Status: Closed Type: Bug Package: Scripting Engine problem PHP Version: Irrelevant Block user comment: N Private report: N New Comment: Automatic comment on behalf of nikic Revision: http://git.php.net/?p=php-src.git;a=commit;h=aad4ecebf83568f41f5b27b274f988710ce53646 Log: Fixed bug #71980 Previous Comments: ------------------------------------------------------------------------ [2016-04-07 06:13:51] nikic@php.net We're leaking the inner generator here. We need to perform partial unfinished execution cleanup before jumping to the finally block. ------------------------------------------------------------------------ [2016-04-06 19:30:24] php at fleshgrinder dot com Description: ------------ The finally block of a Generator that is decorated with or nested in another Generator is never called. This behavior is of course true for multiple decoration or nesting levels. Using a finally block for clean-up in case a Generator is aborted is the official and only way of doing so. It is also recommended in the initial RFC: https://wiki.php.net/rfc/generators#closing_a_generator Please see attached test script as well as expected and actual result. Test script: --------------- #!/usr/bin/env php <?php function generator() { try { while (true) { yield 'Hello'; } } finally { echo "Generator Clean-up\n"; } } function generator_decoration() { try { foreach (generator() as $word) { yield $word . " World!\n"; } } finally { echo "Decorator Clean-up\n"; } } foreach (generator_decoration() as $sentence) { echo $sentence . "Break\n"; break; } echo "Shutdown\n"; Expected result: ---------------- Hello World! Break Decorator Clean-up Generator Clean-up Shutdown Actual result: -------------- Hello World! Break Decorator Clean-up Shutdown Generator Clean-up Workaround: ---------------- In case a frustrated user is finding this bug report. There is a possible workaround that works in all PHP versions that support Generators via a signal that is being sent to the Generator. Please have a look at the following example that makes use of it. #!/usr/bin/env php <?php const GENERATOR_BREAK = 'PHP_GENERATOR_BREAK'; function generator() { try { while (true) { if ((yield 'Hello') === GENERATOR_BREAK) { break; } } } finally { echo "Generator Clean-up\n"; } } function generator_decoration() { $generator = generator(); try { foreach ($generator as $word) { yield $word . " World!\n"; } } finally { echo "Decorator Clean-up\n"; $generator->send(GENERATOR_BREAK); } } foreach (generator_decoration() as $sentence) { echo $sentence . "Break\n"; break; } echo "Shutdown\n"; ------------------------------------------------------------------------ -- Edit this bug report at https://bugs.php.net/bug.php?id=71980&edit=1

« previous php.bugs (#200383) next »