I've updated the closure script and changed the syntax of the inner-lambdas. See this post for the update.
One thing I've always wanted in PHP are closures. I know someone else has already tried to add them in without making a PHP extension, but I decided that I wanted to stay away from PHP's eval. I like the way my solution has turned out except that it requires that get_defined_vars()--or a pseudo args array--be passed in to the first function call instead of automagically figuring that stuff out. Here are some examples how the closures are used...
class Foo
{
public $bar = 'hi';
}
$foo = new Foo;
$anon = lambda(get_defined_vars(), '', '
$foo->bar = "hello";
');
$anon->call();
var_dump($foo);
// gives: object(Foo)#1 (1) { ["bar"]=> string(5) "hello" }
In the previous example, the thing to notice is that object references are preserved throughout the closure. Now here comes a beast... A fixed-point combinator! I modeled this after a javascript example that I found on Douglas Crockford's website. Please realize that for the nested functions I needed to escape the nested single-quotes.
// fixed-point combinator
function Y(Lambda &$le) {
return lambda(get_defined_vars(), 'Lambda $f', '
return $f->call($f);
')->call(lambda(get_defined_vars(), 'Lambda $f', '
return $le->call(lambda(get_defined_vars(), '$x', '
return $f->call($f)->call($x);
'));
'));
}
// anonymous factorial function
$factorial =& Y(lambda(array(), 'Lambda $fac', '
return lambda(get_defined_vars(),'$n', '
return $n <= 2 ? $n : $n * $fac->call($n - 1);
');
'));
echo $factorial->call(5);
// output: 120
As a comparison, it was modeled after:
function Y(le) {
return function (f) {
return f(f);
}(function (f) {
return le(function (x) {
return f(f)(x);
});
});
}
var factorial = Y(function (fac) {
return function (n) {
return n <= 2 ? n : n * fac(n - 1);
};
});
To use this, you need to take the file and also create a folder that the closures can compile to... Yes! They compile! I do not suggest using this script in production code.. mainly because of its heavy use of a singleton as a stack, but then if anyone wants to benchmark this under a heavy load, I'd be very interested to see the results!
Also, I tried to find a hack around having to pass get_defined_vars() as an argument to the "lambda" (Closure) function, but I obviously did not succeed. Anyway, check out the full source of my php closure script at http://ioreader.com/code/php/Closure/closure.phps
As a side note, you might be wondering why I simply didn't use PHP's create_function() to create slightly more lambda-style functions. Check out this comment for more info.
EDIT: I renamed the "C" function to "lambda" and removed the ->scope(...) call so that everything is contained within lambda.
