Search This Blog

5/03/2011

Metaprogramming in PHP

With PHP, you can implement a code of a software that can create another code. It is simple, because a PHP script is a text file.

Although, the language allows you to create a script that modify its own behavior at execution time. It can be useful to optimize stretch of code. This feature is based on "eval" PHP function.

Below, there is an example of code that do not use metaprogramming, and other that do.

In this function, two comparision are made for each iteration:

/**
 * Example function
 * @param array[int] $array Array of integer
 * @param bool $add Whether the values will be added by 1
 * @param bool $multiply Whether the values will be multiplied by 2
 * @return void
 */
function example(array $array, $add, $multiply) {
    foreach ($array as $item) {
        if ($add) {
            $item += 1;
        }
        if ($multiply) {
            $item *= 2;
        }
        echo $item;
    }
}

Using metaprogramming, at first we should create a code dinamically, and then we could execute it with "eval":

/**
 * Example function using metaprogramming
 * @param array[int] $array Array of integer
 * @param bool $add Whether the values will be added by 1
 * @param bool $multiply Whether the values will be multiplied by 2
 * @return void
 */
function example(array $array, $add, $multiply) {
    $code = 'foreach ($array as $item) {';
    if ($add) {
        $code .= '$item += 1;';
    }
    if ($multiply) {
        $code .= '$item *= 2;';
    }
    $code .= 'echo $item;';
    $code .= '}';

    // Execute the value of $code variable
    eval($code);
}

The second example tends to be faster because the $code variable has only the instructions expected and there is no comparision. If we pass the values true and true to $add and multiply, then the generated code would be:

foreach ($array as $item) {
    $item += 1;
    $item *= 2;
    echo $item;
}

Note that there is not any condition.

Although, work with metaprogramming is not recommended to optimize all your code. It could be used in black-box code, where the code is not often consulted, or stretch of code that requires maximum performance. Write a code and put in a variable is a task with many risks, because the interpreter can detect syntax errors only in execution time. This includes instruction delimiter (";"), and all you think.

Metaprogramming take the code less readable and, for that, you have to think well before use it. Although, it ofers feature to create interesting structures. Let's see the code:

$search_code = 'if ($i == $item) { $found = true; $search_code = ""; }';

$item = 7;
for ($i = 0; $i < 10; $i++) {
    eval($search_code);
    echo $i;
}

This code prints numbers from 0 to 9, but it take advantage of the loop iterations to check whether a element was printed or not. When the element is found, there is no reason to find it in the next iteration, so (with metaprogramming) we change the code that make the search. An empty string is a valid PHP code, that is executed very fast, because there is no instructions.

In this example, a variable had keept a code that could change its own value when was evaluated. It could change the code to an other thing (diferent from an empty string). Do you see how metaprogramming can be complex?

No comments:

Post a Comment