How return is working from array_map PHP
I’m fairly new to PHP, but I understand once PHP hits a return in a function, it will exit out of the function and return to where it was called. I am confused to how or why in the function below array_map() starts with return and has another inside the function.
function array_plucked($toPluck, $arr) < return array_map(function($item) use($toPluck) < return $item[$toPluck]; >, $arr); >
Also each time it loops through the array what exactly happening to $item[$toPluck] , and where is the result being stored?
1 Answer 1
Good question! Okay, let’s clean this up a bit:
function array_pluck($key, $array) < return array_map(function ($item) use ($key) < return $item[$key]; >, $array); >
It’s a bit easier to understand this way.
First, the goal of this function is to return a one-dimensional array of the values of a specific key from a multidimensional array. Here are examples:
$testArray = array( array("xxx" => "hello", "yyy" => "goodbye"), array("xxx" => "hi", "yyy" => "bye"), array("xxx" => "hey", "yyy" => "peace"), ); php > var_dump(array_pluck('xxx', $testArray)); array(3) < [0]=>string(5) "hello" [1]=> string(2) "hi" [2]=> string(3) "hey" > php > var_dump(array_pluck('yyy', $testArray)); array(3) < [0]=>string(7) "goodbye" [1]=> string(3) "bye" [2]=> string(5) "peace" > php >
As you can see, this is returning $testArray[][‘xxx’] and $testArray[][‘yyy’] respectively, for each array inside the parent array.
Now to explain what’s going on with the return . The array_map() function takes a function (or «Callable») as the first parameter, and an array as the second parameter. The function is run for each element in the array, and then array_map() adds the return value of that function to the new array that array_map() returns.
It is just like any other function, except it doesn’t have a name, and it does have the use (. ) syntax. The use ($key) means to «import» $key from the outer function ( array_pluck() ), so it can be used inside this anonymous function. Each element of $testArray in the example above, gets passed to this anonymous function as $item . When return $item[$key] occurs, only the anonymous function returns (exits), and the array_map() continues on to the next element.
array_map
array_map() returns an array containing the results of applying the callback to the corresponding value of array (and arrays if more arrays are provided) used as arguments for the callback. The number of parameters that the callback function accepts should match the number of arrays passed to array_map() . Excess input arrays are ignored. An ArgumentCountError is thrown if an insufficient number of arguments is provided.
Parameters
A callable to run for each element in each array.
null can be passed as a value to callback to perform a zip operation on multiple arrays. If only array is provided, array_map() will return the input array.
An array to run through the callback function.
Supplementary variable list of array arguments to run through the callback function.
Return Values
Returns an array containing the results of applying the callback function to the corresponding value of array (and arrays if more arrays are provided) used as arguments for the callback.
The returned array will preserve the keys of the array argument if and only if exactly one array is passed. If more than one array is passed, the returned array will have sequential integer keys.
Changelog
Version | Description |
---|---|
8.0.0 | If callback expects a parameter to be passed by reference, this function will now emit an E_WARNING . |
Examples
Example #1 array_map() example
$a = [ 1 , 2 , 3 , 4 , 5 ];
$b = array_map ( ‘cube’ , $a );
print_r ( $b );
?>
Array ( [0] => 1 [1] => 8 [2] => 27 [3] => 64 [4] => 125 )
Example #2 array_map() using a lambda function
$func = function( int $value ): int return $value * 2 ;
>;
?php
print_r ( array_map ( $func , range ( 1 , 5 )));
print_r ( array_map ( fn ( $value ): int => $value * 2 , range ( 1 , 5 )));
Array ( [0] => 2 [1] => 4 [2] => 6 [3] => 8 [4] => 10 )
Example #3 array_map() — using more arrays
function show_Spanish ( int $n , string $m ): string
return «The number < $n >is called < $m >in Spanish» ;
>
?php
function map_Spanish ( int $n , string $m ): array
return [ $n => $m ];
>
$a = [ 1 , 2 , 3 , 4 , 5 ];
$b = [ ‘uno’ , ‘dos’ , ‘tres’ , ‘cuatro’ , ‘cinco’ ];
$c = array_map ( ‘show_Spanish’ , $a , $b );
print_r ( $c );
$d = array_map ( ‘map_Spanish’ , $a , $b );
print_r ( $d );
?>
The above example will output:
// printout of $c Array ( [0] => The number 1 is called uno in Spanish [1] => The number 2 is called dos in Spanish [2] => The number 3 is called tres in Spanish [3] => The number 4 is called cuatro in Spanish [4] => The number 5 is called cinco in Spanish ) // printout of $d Array ( [0] => Array ( [1] => uno ) [1] => Array ( [2] => dos ) [2] => Array ( [3] => tres ) [3] => Array ( [4] => cuatro ) [4] => Array ( [5] => cinco ) )
Usually when using two or more arrays, they should be of equal length because the callback function is applied in parallel to the corresponding elements. If the arrays are of unequal length, shorter ones will be extended with empty elements to match the length of the longest.
An interesting use of this function is to construct an array of arrays, which can be easily performed by using null as the name of the callback function
Example #4 Performing a zip operation of arrays
$a = [ 1 , 2 , 3 , 4 , 5 ];
$b = [ ‘one’ , ‘two’ , ‘three’ , ‘four’ , ‘five’ ];
$c = [ ‘uno’ , ‘dos’ , ‘tres’ , ‘cuatro’ , ‘cinco’ ];
?php
$d = array_map ( null , $a , $b , $c );
print_r ( $d );
?>
The above example will output:
Array ( [0] => Array ( [0] => 1 [1] => one [2] => uno ) [1] => Array ( [0] => 2 [1] => two [2] => dos ) [2] => Array ( [0] => 3 [1] => three [2] => tres ) [3] => Array ( [0] => 4 [1] => four [2] => cuatro ) [4] => Array ( [0] => 5 [1] => five [2] => cinco ) )
Example #5 null callback with only array
The above example will output:
array(3) < [0]=>int(1) [1]=> int(2) [2]=> int(3) >
Example #6 array_map() — with string keys
$arr = [ ‘stringkey’ => ‘value’ ];
function cb1 ( $a ) return [ $a ];
>
function cb2 ( $a , $b ) return [ $a , $b ];
>
var_dump ( array_map ( ‘cb1’ , $arr ));
var_dump ( array_map ( ‘cb2’ , $arr , $arr ));
var_dump ( array_map ( null , $arr ));
var_dump ( array_map ( null , $arr , $arr ));
?>?php
The above example will output:
array(1) < ["stringkey"]=>array(1) < [0]=>string(5) "value" > > array(1) < [0]=>array(2) < [0]=>string(5) "value" [1]=> string(5) "value" > > array(1) < ["stringkey"]=>string(5) "value" > array(1) < [0]=>array(2) < [0]=>string(5) "value" [1]=> string(5) "value" > >
Example #7 array_map() — associative arrays
While array_map() does not directly support using the array key as an input, that may be simulated using array_keys() .
$arr = [
‘v1’ => ‘First release’ ,
‘v2’ => ‘Second release’ ,
‘v3’ => ‘Third release’ ,
];
?php
// Note: Before 7.4.0, use the longer syntax for anonymous functions instead.
$callback = fn ( string $k , string $v ): string => » $k was the $v » ;
$result = array_map ( $callback , array_keys ( $arr ), array_values ( $arr ));
The above example will output:
array(3) < [0]=>string(24) "v1 was the First release" [1]=> string(25) "v2 was the Second release" [2]=> string(24) "v3 was the Third release" >
See Also
- array_filter() — Filters elements of an array using a callback function
- array_reduce() — Iteratively reduce the array to a single value using a callback function
- array_walk() — Apply a user supplied function to every member of an array
User Contributed Notes 9 notes
Let’s assume we have following situation:
class MyFilterClass public function filter (array $arr ) return array_map (function( $value ) return $this -> privateFilterMethod ( $value );
>);
>
private function privateFilterMethod ( $value ) if ( is_numeric ( $value )) $value ++;
else $value .= ‘.’ ;
>
>
?>
This will work, because $this inside anonymous function (unlike for example javascript) is the instance of MyFilterClass inside which we called it.
I hope this would be useful for anyone.
Find an interesting thing that in array_map’s callable function, late static binding does not work:
class A public static function foo ( $name ) return ‘In A: ‘ . $name ;
>
public static function test ( $names ) return array_map (function( $n ) , $names );
>
>
class B extends A public static function foo ( $name ) return ‘In B: ‘ . $name ;
>
>
$result = B :: test ([ ‘alice’ , ‘bob’ ]);
var_dump ( $result );
?>
the result is:
array (size=2)
0 => string ‘In A: alice’ (length=11)
1 => string ‘In A: bob’ (length=9)
if I change A::test to
public static function test ( $names ) return array_map ([ get_called_class (), ‘foo’ ], $names );
>
?>
Then the result is as expected:
array (size=2)
0 => string ‘In B: alice’ (length=11)
1 => string ‘In B: bob’ (length=9)
To transpose rectangular two-dimension array, use the following code:
array_unshift($array, null);
$array = call_user_func_array(«array_map», $array);
If you need to rotate rectangular two-dimension array on 90 degree, add the following line before or after (depending on the rotation direction you need) the code above:
$array = array_reverse($array);
$a = array(
array( 1 , 2 , 3 ),
array( 4 , 5 , 6 ));
array_unshift ( $a , null );
$a = call_user_func_array ( «array_map» , $a );
print_r ( $a );
?>
Output:
You may be looking for a method to extract values of a multidimensional array on a conditional basis (i.e. a mixture between array_map and array_filter) other than a for/foreach loop. If so, you can take advantage of the fact that 1) the callback method on array_map returns null if no explicit return value is specified (as with everything else) and 2) array_filter with no arguments removes falsy values.
So for example, provided you have:
$data = [
[
«name» => «John» ,
«smoker» => false
],
[
«name» => «Mary» ,
«smoker» => true
],
[
«name» => «Peter» ,
«smoker» => false
],
[
«name» => «Tony» ,
«smoker» => true
]];
?>
You can extract the names of all the non-smokers with the following one-liner:
$names = array_filter ( array_map (function( $n ) < if(! $n [ 'smoker' ]) return $n [ 'name' ]; >, $data ));
?>
It’s not necessarily better than a for/foreach loop, but the occasional one-liner for trivial tasks can help keep your code cleaner.
A general solution for the problem of wanting to know the keys in the callback, and/or retain the key association in the returned array:
/**
* Like array_map() but callback also gets passed the current key as the
* first argument like so:
* function($key, $val, . $vals) < . >
* . and returned array always maintains key association, even if multiple
* array arguments are passed.
*/
function array_map_assoc (callable $callback , array $array , array . $arrays ) $keys = array_keys ( $array );
array_unshift ( $arrays , $keys , $array );
return array_combine ( $keys , array_map ( $callback , . $arrays ));
>
?>
Because it uses array_map() directly, it behaves the same way in regard to ignoring the keys of subsequent array arguments. It also has the same variadic signature.
If you want to pass an argument like ENT_QUOTES to htmlentities, you can do the follow.
$array = array_map ( ‘htmlentities’ , $array , array_fill ( 0 , count ( $array ) , ENT_QUOTES ) );
?>
The third argument creates an equal sized array of $array filled with the parameter you want to give with your callback function.
The most memory-efficient array_map_recursive().
function array_map_recursive (callable $func , array $arr ) array_walk_recursive ( $arr , function(& $v ) use ( $func ) $v = $func ( $v );
>);
return $arr ;
>
?>
/**
* Function which recursively applies a callback to all values and also its
* keys, and returns the resulting array copy with the updated keys and
* values.
* PHP’s built-in function array_walk_recursive() only applies the passed
* callback to the array values, not the keys, so this function simply applies
* the callback to the keys too (hence the need of working with a copy,
* as also updating the keys would lead to reference loss of the original
* array). I needed something like this, hence my idea of sharing it here.
*
* @param callable $func callback which takes one parameter (value
* or key to be updated) and returns its
* updated value
*
* @param array $arr array of which keys and values shall be
* get updated
*/
function array_map_recursive(
callable $func,
array $arr
)
// Initiate copied array which will hold all updated keys + values
$result = [];
// Iterate through the key-value pairs of the array
foreach ( $arr as $key => $value )
// Apply the callback to the key to create the updated key value
$updated_key = $func( $key );
// If the iterated value is not an array, that means we have reached the
// deepest array level for the iterated key, so in that case, assign
// the updated value to the updated key value in the final output array
if ( ! is_array( $value ) )
$result[$updated_key] = $func( $value );
// If the iterated value is an array, call the function recursively,
// By taking the currently iterated value as the $arr argument
$result[$updated_key] = array_map_recursive(
$func,
$arr[$key]
);
> // end of iteration through k-v pairs
// And at the very end, return the generated result set
return $result;
> // end of array_map_recursive() function definition