php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Request #61790 Feature Request for create_closure() function
Submitted: 2012-04-20 15:55 UTC Modified: 2012-04-23 00:36 UTC
Votes:1
Avg. Score:3.0 ± 0.0
Reproduced:1 of 1 (100.0%)
Same Version:1 (100.0%)
Same OS:0 (0.0%)
From: thegreatall at gmail dot com Assigned:
Status: Wont fix Package: *Programming Data Structures
PHP Version: Irrelevant OS: N/A
Private report: No CVE-ID: None
Have you experienced this issue?
Rate the importance of this bug to you:

 [2012-04-20 15:55 UTC] thegreatall at gmail dot com
Description:
------------
As I am sure many of you know of the create_function() function, but this 
actually creates a named function in the global scope. This can be undesirable 
if a user is creating an unknown number of functions because it fills memory 
with named execution points but once the variable looses it's references it 
should be cleaned up by the garbage collector.

I am asking for a create_closure() function to do the same thing that 
create_function does, but return a closure instead of a string containing the 
name to a newly created named function.

You can simulate a function like this using eval, but we all know the evils of 
eval.

An example of why someone would like to do this:
A developer creates a framework which handles classes to records in the 
database. When records get updated/created/pulled it has a "hooks" on the record 
level that allows custom "hooks" to be installed on the record and executed on 
the specific records. The code for the hook is not accessible/modifiable by the 
user only the developers that have database access, but each user may install 
that hook on a specific record. So if we had a hook that IMs users when specific 
records are modified in the database and 5000 users want this hook installed on 
that record it installs 5000 hooks on this record and creates 5000 named 
functions but each function would only be executed once and can/should be 
cleaned by the garbage collector. (I know there is a more optimal way to achieve 
this specific example, but if I need to change the list of arguments it has to 
recompile the function creating a new named function. This is not an issue with 
closures because they are not named functions and the garbage collector cleans 
them up after they are de-referenced.

Test script:
---------------
<?php
// Example 1
function create_fn($i){
	return eval('return function ($g){
		echo "'.$i.' - $g\n";
	};');
}
for($i=0;$i<100000;$i++){
	$fn = create_fn($i);
	if($i % 10000 == 0)
		$fn(memory_get_usage(true));
}


<?php
// Example 2
function create_fn($i){
	return function ($g) use ($i){
		echo "$i - $g\n";
	};
}
for($i=0;$i<100000;$i++){
	$fn = create_fn($i);
	if($i % 10000 == 0)
		$fn(memory_get_usage(true));
}


<?php
// Example 1
function create_fn($i){
	return create_function('$g', 'echo "'.$i.' - $g\n";');
}
for($i=0;$i<100000;$i++){
	$fn = create_fn($i);
	if($i % 10000 == 0)
		$fn(memory_get_usage(true));
}

Expected result:
----------------
Result 1: (slower than 2, does NOT snowball memory)
count - memory
-----------------------
0 - 262144
10000 - 4194304
20000 - 4194304
30000 - 4194304
40000 - 4194304
50000 - 4194304
60000 - 4194304
70000 - 4194304
80000 - 4194304
90000 - 4194304

Result 2: (really fast consumes very little memory)
count - memory
-----------------------
0 - 262144
10000 - 262144
20000 - 262144
30000 - 262144
40000 - 262144
50000 - 262144
60000 - 262144
70000 - 262144
80000 - 262144
90000 - 262144


Result 3:
count - memory (slow and consumes tons of memory and snowballs memory)
-----------------------
0 - 262144
10000 - 8126464
20000 - 16515072
30000 - 24641536
40000 - 31981568
50000 - 39583744
60000 - 47185920
70000 - 54525952
80000 - 62128128
90000 - 69730304


Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2012-04-20 19:46 UTC] nikic@php.net
I'm not sure I understand your issue. create_function() is just a wrapper around eval(). The evils of eval() are also the evils of create_function().

And, as you showed, this is trivial to implement in userland.

I really wouldn't like PHP to add further functions encouraging bad coding style.
 [2012-04-23 00:36 UTC] aharvey@php.net
-Status: Open +Status: Wont fix
 [2012-04-23 00:36 UTC] aharvey@php.net
I think Nikita's covered this well. create_function() is just eval() in a slight 
cloak anyway, and given that the two are generally discouraged, I don't think 
there's much reason to add another function in the same ilk when it can be 
emulated in userspace at the cost of slightly polluting the global function table.
 
PHP Copyright © 2001-2019 The PHP Group
All rights reserved.
Last updated: Fri Jul 19 04:01:25 2019 UTC