Edit report at https://bugs.php.net/bug.php?id=62452&edit=1

 ID:                 62452
 Comment by:         ni...@php.net
 Reported by:        hanskrentel at yahoo dot de
 Summary:            Variable Aliasing does not work in Closure
 Status:             Re-Opened
 Type:               Bug
 Package:            Scripting Engine problem
 Operating System:   Multiple
 PHP Version:        Irrelevant
 Block user comment: N
 Private report:     N

 New Comment:

I just looked into this a bit but couldn't find a good way to fix it. The main 
issue is that the prototype hack is only done in ZEND_INIT_FCALL_BY_NAME and 
only for VARs. Doing the same for CVs (as in this case) would be easy, but it 
sadly does not work properly if the closure is also invoked using 
call_user_func or any other function using zend_call_function internally. 
zend_call_function does not back the closure into the prototype and due to the 
way it works I'm not sure how this could be added there. For zcf the 
get_closure object handler call is done within zend_is_callable_ex and the 
results are put into the passed function_call_cache then. But the fcc can be 
reused for multiple calls (or not be used at all), so I really don't know how 
to do this safely without causing leaks or double frees.


Previous Comments:
------------------------------------------------------------------------
[2012-07-03 17:49:27] ni...@php.net

@laruence: The closure can still exist even if it is not referenced by $f 
anymore. I didn't look into this yet, but the fix should be along the lines of 
adding a ref to the closure when it is called and removing it again when it 
finishes running. Actually, I remember seeing something in the code that backs 
up the function zval into op_array.prototype (disguised as a zend_function*) 
and dtors it in the leave_helper. But clearly that isn't enough yet.

------------------------------------------------------------------------
[2012-07-03 17:39:24] hanskrentel at yahoo dot de

hi @laurence, thank's for taking the time to review it. If I write code like

unset($this);

it does not fatal error either (you can not destroy a object while you are 
calling 
it.).

Also I don't want to destroy the closure, I just want to re-use that variable. 
Can't you just let the garbage collector do the dirty work?

------------------------------------------------------------------------
[2012-07-02 07:03:19] larue...@php.net

you can not destroy a closure while you are calling it.

when you override $f in $f, zend vm try to destroy the closure $f, since the 
refcout of it is 1.

try following :

$b = $f = function() use (&$f) {
    $f = function() {};
};
$f();
$f();

------------------------------------------------------------------------
[2012-06-29 20:05:06] ni...@php.net

Verified on master.

------------------------------------------------------------------------
[2012-06-29 19:53:22] hanskrentel at yahoo dot de

Description:
------------
It's not possible to make use of variable aliasing in PHP when the alias is 
used 
within the use clause of a lambda function construct that is assigned to that 
variable (recursion).

PHP denies to do what it is commanded with a Fatal error: Cannot destroy active 
lambda function. But the function is not destroyed. It's just not that the 
variable container contains the identifier of it.

I'd like to change that, and I don't want to waste another variable name. Also 
I 
don't understand how I can actually destroy something I should not have any 
access 
to from PHP userland.

Or if that is intended, please allow us to destroy the active lambda making the 
function return NULL and continue to execute.



Test script:
---------------
$f = function() use (&$f) {
    $f = function() {echo "hello"};
};
$f();
$f();


Expected result:
----------------
hello

Actual result:
--------------
Fatal error: Cannot destroy active lambda function 


------------------------------------------------------------------------



-- 
Edit this bug report at https://bugs.php.net/bug.php?id=62452&edit=1

Reply via email to