5

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?

Pacerier
  • 86,231
  • 106
  • 366
  • 634
user2301515
  • 4,903
  • 6
  • 30
  • 46
  • 3
    Short answer: You can't. PHP 5.3 has features that aren't in 5.2, and can't be replicated in 5.2. This is one of them. – Spudley Apr 23 '13 at 15:26
  • 1
    Also, it's worth pointing out to whoever is asking to you work in 5.2 that the PHP devs declared 5.2 end-of-life more than two years ago; it hasn't had any patches since then and has a number of known security holes. Anyone still using it on a production server after all this time is guilty of neglegence. – Spudley Apr 23 '13 at 15:28

4 Answers4

3

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.

Community
  • 1
  • 1
Pacerier
  • 86,231
  • 106
  • 366
  • 634
  • So sick of everyone just telling me to upgrade the PHP version, like I wouldn't if I had that option. Thank you for providing some excellent alternative solutions. – mynameispaulie Mar 23 '16 at 14:48
2

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).

webbiedave
  • 48,414
  • 8
  • 88
  • 101
  • **This can be done** using global and/or serializing. See [my answer](http://stackoverflow.com/a/30436890/632951) just below. – Pacerier Nov 26 '15 at 09:34
0

You can use global like so:

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

However, you really should be upgrading PHP, not worrying about downgrading :p

Niet the Dark Absol
  • 320,036
  • 81
  • 464
  • 592
  • globals are as close as you'll get, and will probably work in this case, but please note that this isn't actually a direct equivalent, because `use()` provides a reference to the variable in the context of the original function at the point where the closure is created, whereas a global is.. well, a global. For example, if a closure is referenced in a loop, you could `use()` the looped array element, but as a global, you'd have to provide the whole array plus the key you wanted to reference, or some other work around. Really not ideal. – Spudley Apr 23 '13 at 15:33
0

You can make use of serialize/unserialize, as in:

create_function('$e','return $e % unserialize(\''.serialize($nr).'\') == 0;')
analpaper
  • 1
  • 1
  • 1