Bug #71980 [NEW]: Decorated/Nested Generator is Uncloseable in Finally
| From: | php at fleshgrinder dot com | Date: | Wed, 06 Apr 2016 19:30:27 +0000 |
| Subject: | Bug #71980 [NEW]: Decorated/Nested Generator is Uncloseable in Finally | ||
| Groups: | php.bugs | ||
| Request: | Send a blank email to php-bugs+get-200399@lists.php.net to get a copy of this message | ||
From: php at fleshgrinder dot com
Operating system:
PHP version: Irrelevant
Package: Scripting Engine problem
Bug Type: Bug
Bug description:Decorated/Nested Generator is Uncloseable in Finally
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 bug report at https://bugs.php.net/bug.php?id=71980&edit=1
--
Try a snapshot (PHP 5.4): https://bugs.php.net/fix.php?id=71980&r=trysnapshot54
Try a snapshot (PHP 5.5): https://bugs.php.net/fix.php?id=71980&r=trysnapshot55
Try a snapshot (trunk): https://bugs.php.net/fix.php?id=71980&r=trysnapshottrunk
Fixed in SVN: https://bugs.php.net/fix.php?id=71980&r=fixed
Fixed in release: https://bugs.php.net/fix.php?id=71980&r=alreadyfixed
Need backtrace: https://bugs.php.net/fix.php?id=71980&r=needtrace
Need Reproduce Script: https://bugs.php.net/fix.php?id=71980&r=needscript
Try newer version: https://bugs.php.net/fix.php?id=71980&r=oldversion
Not developer issue: https://bugs.php.net/fix.php?id=71980&r=support
Expected behavior: https://bugs.php.net/fix.php?id=71980&r=notwrong
Not enough info: https://bugs.php.net/fix.php?id=71980&r=notenoughinfo
Submitted twice: https://bugs.php.net/fix.php?id=71980&r=submittedtwice
register_globals: https://bugs.php.net/fix.php?id=71980&r=globals
PHP 4 support discontinued: https://bugs.php.net/fix.php?id=71980&r=php4
Daylight Savings: https://bugs.php.net/fix.php?id=71980&r=dst
IIS Stability: https://bugs.php.net/fix.php?id=71980&r=isapi
Install GNU Sed: https://bugs.php.net/fix.php?id=71980&r=gnused
Floating point limitations: https://bugs.php.net/fix.php?id=71980&r=float
No Zend Extensions: https://bugs.php.net/fix.php?id=71980&r=nozend
MySQL Configuration Error: https://bugs.php.net/fix.php?id=71980&r=mysqlcfg