RSS Feed

Peter Goodman's blog about PHP, Parsing Theory, C++, Functional Programming, Applications,

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


Comment