Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHP < 5.3, create_function and use variable

Tags:

php

I'm trying to convert some PHP 5.3 code into PHP 5.2 (which doesn't support anonymous functions) . This is the PHP 5.3 code:

$nr = 2;
$a = array(1,2,3,4,5,6,7,8,9,10);
$a = array_filter($a,function($e) use($nr) {
    return $e % $nr == 0;
});

My conversion is as such:

array_filter($a,create_function('$e','return $e % $nr == 0;'));

Where should the use($nr) be placed?

like image 961
user2301515 Avatar asked Apr 23 '13 15:04

user2301515


2 Answers

Option 1: Global access

global will work fine actually: code link

<?php
$nr = 2;
$a = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
$a = array_filter($a, create_function('$e', '
    global $nr;
    return $e % $nr == 0;
'));
var_dump($a);

This effectively gives us "JavaScript style" access whereby there's only one copy of the variable, and any writes made to that variable will be seen everywhere else:

<script> // javascript code:
var a = 1;
(function(){
    a = 2; 
})();
console.log(a); // javascript shows 2
</script>

However, note that the functionality provided by "JavaScript style" access differs from use, because use copies the values when the function is defined. This means that via use, there are multiple copies of the variables and modifying one would not affect the other:

<?php
$a = 1;
call_user_func(function()use($a){
    $a = 2;
});
var_dump($a); // php shows 1

To achieve this functionality (so that we can do a "perfect shim"), you must ensure that you do not assign new values to the globalized variables. If you need to assign new values to the variables,

If you need to modify your original value, you may want to first create a copy of it, and then globalize that copy. This way, your original value is not bounded and can be modified: code link

<?php
$nr = 2;
$nr_copy = 2;
$a = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
$nr = 3; // you can freely modify $nr because the function below is using $nr_copy
$a = array_filter($a, create_function('$e', '
    global $nr_copy;
    return $e % $nr_copy == 0;
'));
var_dump($a);

Note that Option 1 (global) doesn't work if the variable you need to refer to is within a function's scope:

<?php
some_function();
function some_function(){
    $nr = 2;
    $a = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
    $a = array_filter($a, create_function('$e', '
        global $nr; // this will not work because $nr is undefined
        return $e % $nr == 0;
    '));
    var_dump($a);
}

For such cases, you have no choice but to use Option 2.


Option 2: Concatenation

You can superimpose the value directly into the function's definition: code link

<?php
some_function();
function some_function(){
    $nr = 2;
    $a = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
    $a = array_filter($a, create_function('$e', '
        return $e % '.$nr.' == 0;
    '));
    var_dump($a);
}

In cases where simple concatenation don't work (e.g. for arrays and objects), the only option is serializing: code link

<?php
some_function();
function some_function(){
    $nr = 2;
    $a = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
    $a = array_filter($a, create_function('$e', '
        return $e % unserialize(\''.str_replace("'", "\'", serialize($nr)).'\') == 0;
    '));
    var_dump($a);
}

The idea is simply to convert the variable into a string that you can insert within the function body.

like image 92
Pacerier Avatar answered Nov 20 '22 07:11

Pacerier


PHP 5.2 doesn't support Closures. Hence, you can't use the use keyword.

If you need your code to be 5.2 compatible, you would be better off just creating a named function/method and pass in the necessary parameters rather using create_function as the latter can cause memory leaks (new function is created each time and gc doesn't catch them all).

like image 25
webbiedave Avatar answered Nov 20 '22 05:11

webbiedave