Hacking Variable Composition: Another Approach to PHP Lambdas
I was fooling around with variable composition today and had a cool idea. Before that, if you don't know what variable composition is then here are some examples of the neat manipulations PHP lets you do with variables.
// variable variables
$foo = 'bar';
$bar = 'hello';
echo $$foo; // outputs: 'hello'
// variable composition
$foo = 'bar';
echo ${'foo'}; // outputs: 'bar'
Essentially it is just different syntax for variables. However, with the right techniques, we can make it into so much more. For example, here is a composed variable that will actually execute a database UPDATE query:
<pre lang="php">
// fake db query
function db_query($sql) {
// do query here...
echo $sql;
}
function query_error_handler($error_num, $error_str, $error_file, $error_line) {
if($error_num == 8 && preg_match("~^Undefined variable: update~i", $error_str)) {
return db_query(str_ireplace('Undefined variable: ', '', $error_str));
}
return FALSE;
}
set_error_handler('query_error_handler');
// perform a db query
!${"UPDATE mytable SET foo='bar'"};
You should be able to determine just from looking at this that you shouldn't use this type of hack in production code. Otherwise, for the curious programmer, it's definitely an interesting line to pursue. Now, on to Lambdas. My last article on closures/lambdas fixed a few bugs in my system and cleaned up the code; however, there was still the annoying of having to used ->call() to call the function. Essentially, I want to be able to do: lambda(...)(arg1[, arg1[, arg3[, ....]]]). Unfortunately this cannot be done. However, it can be approximated with variable composition. Check this out:
$lambda_1;
function lambda($args = '', $content = '') {
global $lambda_1;
$lambda_1 = create_function($args, $content);
return 'lambda_1';
}
echo ${lambda('$a', 'return $a;')}('hello world');
// output: 'hello world'
Clearly this code was set up specifically for this example, however I definitely think that this can be built on.
Comments
-
I find the variable composition extremely useful, for instance if you're creating a Factory - often in a Factory pattern you will need to dynamically call constructors or methods. Normally I would do it like this: $someMethodPrefix = 'populate'; $myDynamicParameter = 'MyClass'; $method = $someMethodPrefix . $myDynamicParameter; $this->$method(); // $this->populateMyClasss(); Now, I can do it in a one-liner like this: $this->{$someMethodPrefix.$myDynamicParameter}(); Thanks :)
posted by Carl on Aug 20, 2007 at 9:42am -
My eyes! The goggles do nothing!
posted by Ranier Wolfcastle on Aug 20, 2007 at 8:54am -
Technically a self calling function would be a callback function for an event, which of course does not exist in PHP. Nor is it supposed to, it's simply not the way PHP functions, if you need event based programming then go with a C# backend instead of using PHP.
posted by Seph on Aug 19, 2007 at 6:37pm -
Hey, sorry for being late to the party but check this out: //L is for lambda $L = Array(); function lambda($args = '', $content = '') { global $L; $name = create_function($args, $content); $L[$name] = $name; return $name; } //and now you can do: echo $L[lambda('$x','return $x;')]('hello world'); //and again echo $L[lambda('$y','return $x*x;')](3.14);
posted by shaunxcode on May 18, 2008 at 1:10am -
As a side note, one of the things I dislike most with PHP is that functions are not objects and thus cannot be self-calling. The above hack using create_function semi solved the self-calling issue.
posted by Peter Goodman on Aug 18, 2007 at 12:19pm -
Wow? Hackish? Insightful? No, it isn't. What's the difference between that and using "create_function" directly? Exactly none. In fact, you cannot assign several "lambda" results to variables and pass them around, as every one would refer in fact to a string with the name of the same global (gasp!) variable. Programmer baby Jesus is already crying. If you want to fool yourself with the idea that PHP has functional constructs, just assign the result of "create_function" to $func and use it with $func(params). Good luck if you use that, though. That "lambda" thing of yours is nothing more than syntax saccharine (not even sugar) with zero practical value and many, many problems (ugliness is the least of them). Sorry if I sound harsh, but this is what I think.
posted by Kankamuso on Aug 18, 2007 at 12:07pm -
In most ways you are right, this is not practical, it does not solve a problem, and it's generally quite an ugly solution. However, the goal of this was to look at php's limitations as a challenge and try to come up with a proof-of-concept way to call lambda-like functions at their creation instead of after their assignment. In this respect, I succeeded. I disagree with you that this code isn't insightful. As I've mentioned, this does not solve any realistic problems in PHP, and with respect to solving problems it is lacking insight. However, experimentation is healthy and I think that this was an insightful solution to the problem (or rather, a challenge to myself) of calling a created function on the spot.
posted by Peter Goodman on Aug 18, 2007 at 12:14pm -
Wow. While you're right that the technique is too hackish to use in production code, it's still amazingly insightful. On the first look through, it looked more like JavaScript's Prototype than PHP. I'm looking forward to seeing what all you can do with this.
posted by Brian Bosh on Jun 19, 2007 at 9:05am
Comment
