How can i pass a single additional argument to array_map callback in PHP?
Asked Answered
C

2

18

How can i pass a single additional argument to array_map callback? In my example i'd like to pass $smsPattern (as a second argument, after current element in $featureNames) to the function array_map with $getLimit closure:

$features = $usage->getSubscription()->getUser()->getRoles();

// SMS regular expression in the form of ROLE_SEND_SMS_X
$smsPattern = '/^ROLE_SEND_SMS_(?P<l>\d+)$/i';

// Function to get roles names and X from a role name
$getNames = function($r) { return trim($r->getRole()); };
$getLimit = function($name, $pattern) {
    if(preg_match($pattern, $name, $m)) return $m['l'];
};

// Get roles names and their limits ignoring null values with array_filter
$featuresNames = array_map($getNames, $features);
$smsLimits     = array_filter(array_map($getLimit,  $featureNames, $smsPattern));

With this code i'm getting a weird warning:

Warning: array_map() [function.array-map]: Argument #3 should be an array.

Of course di reason is for reusing $getLimit closure with another regular expression like $smsPattern. Thanks.

Clematis answered 3/6, 2012 at 16:37 Comment(4)
Why not use array_walk() instead, then you can pass an additional argumentSniffy
What are you using array_filter for?Jovia
@EmilVikström removing null values.Clematis
Ok! I didn't even know that array_filter worked without a callback. Now I know, and I have added it to my answer as well.Jovia
G
42

This is exactly what closures are about:

$getLimit = function($name) use ($smsPattern) {
    if(preg_match($smsPattern, $name, $m)) return $m['l'];
};

$smsLimits = array_filter(array_map($getLimit, $features));

If you want to generalize it to other patterns, wrap the function creation into another function:

function patternMatcher($pattern) {
    return function($name) use ($pattern) {
        if(preg_match($pattern, $name, $m)) return $m['l'];
    };
}

$getLimit = patternMatcher($smsPattern);
$smsLimits = array_filter(array_map($getLimit, $features));

And here it is wrapped up as an anonymous function:

$patternMatcher = function($pattern) {
    return function($name) use ($pattern) {
        if(preg_match($pattern, $name, $m)) return $m['l'];
    };
};

$smsLimits = array_filter(array_map($patternMatcher($smsPattern), $features));
Guernica answered 3/6, 2012 at 16:43 Comment(0)
H
0

As outlined in the docs, you can pass additional arguments to array_map() after your array. The catch is that the argument must be an array. Each value in this array is passed to the callback along with it's corresponding index in the array being processed, so you'd like them to be the same length. If you only have a single argument that you want to use for each and every iteration, you can use array_fill() to populate an array of arguments like this:

$smsLimits = array_map(
    $getLimit,
    $featureNames,
    array_fill(0, count($featureNames), $smsPattern)
);

A common use case is where you might want to trim a single character like / from an array of urls:

$urls = ['http://example.com/','http://sub.example.com/'];
$urls = array_map('rtrim', $urls, array_fill(0, count($urls), '/'));

Which would result in:

Array
(
    [0] => http://example.com
    [1] => http://sub.example.com
)
Hydrate answered 25/2, 2020 at 18:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.