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.

4
  • Why not use array_walk() instead, then you can pass an additional argument Commented Jun 3, 2012 at 16:40
  • What are you using array_filter for? Commented Jun 3, 2012 at 16:44
  • @EmilVikström removing null values. Commented Jun 3, 2012 at 19:24
  • 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. Commented Jun 3, 2012 at 19:32

2 Answers 2

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));
Sign up to request clarification or add additional context in comments.

Comments

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
)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.