Dynamic array_multisort() without calling deprecated function create_function()

342 views Asked by At

I have this function in my old php5 code that will accept a variable number of parameters and perform sorting based on the parameters:

function array_alternate_multisort(){
    $arguments = func_get_args();
    $arrays     = $arguments[0];
    for ($c = (count($arguments)-1); $c > 0; $c--)
    {
        if (in_array($arguments[$c], array(SORT_ASC , SORT_DESC)))
        {
                continue;
        }
        $compare = create_function('$a,$b','return strcasecmp($a["'.$arguments[$c].'"], $b["'.$arguments[$c].'"]);');
        usort($arrays, $compare);
        if ($arguments[$c+1] == SORT_DESC)
        {
                $arrays = array_reverse($arrays);
        }
    }
    return $arrays ;
}

I call it like this:

$alliances = array_alternate_multisort($alliances, "output", SORT_DESC, "score", SORT_DESC);

How can I replace this with a function without calling create_function()?

2

There are 2 answers

0
M. Eriksson On BEST ANSWER

You can use an anonymous function instead:

$compare = function ($a, $b) use ($arguments, $c) {
    return strcasecmp($a[$arguments[$c]], $b[$arguments[$c]]);
};

Untested but should be close enough

The use keyword allows you to inherit variables from the parent scope inside your function.

0
mickmackusa On

First of all, I'll argue that if you have the ability to hardcode this into your script:

$alliances = array_alternate_multisort($alliances, "output", SORT_DESC, "score", SORT_DESC);

then you can just as easily completely scrap your custom function and just write this:

Code: (Demo)

array_multisort(...[
    array_column($alliances, 'output'),
    SORT_DESC,
    array_column($alliances, 'score'),
    SORT_DESC,
    &$alliances
]);

This will do EVERYTHING that your custom function will do and more WITHOUT introducing ANY custom function.

This is a very concise, totally native, and instantly readable technique. Using this means that:

  • you will not confine your script to only SORT_ASC and SORT_DESC; there are other useful sorting flags to enjoy for specific scenarios.
  • you can opt to omit the sorting direction parameters if you wish to use SORT_ASC (the default sorting flag).
  • you modify the input array by reference like other native sorting functions.

Now anything beyond the above is going to introduce unnecessary convolution. To keep this hypothetical (which, again, I don't endorse) demonstration simple I'll insist that the sorting direction flags are required like in your original snippet.

Code: (Demo)

function array_alternate_multisort($array, ...$args) {
    foreach ($args as $i => $arg) {
        $sortParams[] = $i & 1 ? $arg : array_column($array, $arg);
    }
    $sortParams[] = &$array;
    array_multisort(...$sortParams);
    return $array;
}
  • & 1 is a bitwise odd check. If the index is odd, push the constant into $sortParams otherwise push the column data into $sortParams.

This answer belongs to a family of similar answers that use the splat operator to unpack parameters into a array_multisort() call.