Question

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.

Was it helpful?

Solution

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

OTHER TIPS

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
)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top