T.Todua
T.Todua

Reputation: 56371

Using array_map with multi-argument function?

I am building a recursive function, which executes any function for any-deep-nested-array. For example, I want to STRIPSLASH all array values in this:

function RECURSER($array,$function_name){ 
   return is_array($array) ? array_map('RECURSER', $array, $function_name) : $function_name($array); 
}

but when I execute:

recursive_for_array_value( $MY_ARRAY, 'stripslashes')

the above function can't send second parameter to array_map.

Upvotes: 1

Views: 460

Answers (3)

mickmackusa
mickmackusa

Reputation: 47894

Now I'll start off by saying that I'd probably never use this in any real projects, but this is an interesting challenge/question and T.Todua's answer works but using $GLOBALS can be avoided.

My position is that array_walk_recursive() is a better suited function versus recursively calling array_map() -- after all, array_walk_recursive() was specifically designed to visit leaf nodes and avoid the tedium of checking the current item's type as "array". use() is effective in passing the function string into the recursive function's scope.

*Note: You could only pass the function string as a string in a SUPER fringe case where the function prints to screen AND requires two arguments -- the first arg being the element value and the second arg being the element key.

Because you want to only process the element values AND modify them by reference, &$v is necessary.

Here is a relevant post to read regarding checking the dynamic function name: What exactly is the difference between the is_callable and function_exists in PHP?

Here is my working alternative:

Code: (Demo)

$multidim_array = ['a' => [' \one ', ['b' => 'two\\', [['c' => 'thr\ee']]]]];
$func = 'stripslashes';
if (function_exists($func)) {
    array_walk_recursive($multidim_array, function(&$v)use($func){$v = $func($v);});
    var_export($multidim_array);
} else {
    echo "not callable";
}

If you wanted to go down this rabbit hole further, you could extend its potential utility by setting up the option to pass multiple arguments:

Code: (Demo)

$func = 'strpos';
if (function_exists($func)) {
    $more = true;
    $param2 = 'o';
    array_walk_recursive($multidim_array, function(&$v)use($func, $more, $param2) {
        if ($more) {
            $v = $func($v, $param2);
        } else {
            $v = $func($v);
        }
    });
    var_export($multidim_array);
} else {
    echo "um... I'm not calling $func";
}

Finally, the approach that I whole-heartedly do NOT endorse is the use of eval() -- because you can see the tail, horns, and pitchfork a mile away.

Caution The eval() language construct is very dangerous because it allows execution of arbitrary PHP code. Its use thus is discouraged. If you have carefully verified that there is no other option than to use this construct, pay special attention not to pass any user provided data into it without properly validating it beforehand.

This works, but really should not be entertained:

if (function_exists($func)) {
    array_walk_recursive($multidim_array, function(&$v)use($func) {eval("\$v = $func(\$v);"); });
    var_export($multidim_array);
} else {
    echo "um... I'm not calling $func";
}

Upvotes: 2

apokryfos
apokryfos

Reputation: 40663

array_map accepts one function and multiple arrays as arguments. Perhaps you need to recursively call recurser via an anonymous function instead.

function RECURSER($array,$function_name){ 
     if (is_array($array))
        return array_map(function ($element) use ($function_name) {
           return RECURSER($element,$function_name);
       },$array);                
   return $function_name($array);
}

The usecase of stripslashes as a one-line PHP function can be written as :

array_walk_recursive($array, function (&$value) { $value = stripslashes($value); });

Upvotes: 1

T.Todua
T.Todua

Reputation: 56371

RECURSOR of any function:

$result= Recursiver_of_Array($array, 'stripslashes');

code:

function Recursiver_of_Array($array,$function_name=false){ 
    if ($function_name) { $GLOBALS['current_func_name']= $function_name; }
    return is_array($array) ? array_map('Recursiver_of_Array', $array) : $GLOBALS['current_func_name']($array); 
}

Upvotes: 1

Related Questions