I'm proposing a new function similar to the implementation of array_map
that allows us to apply a user-supplied callback to every element in the
array with the addition of the callback being passed the key as well as the
value of each element. Additionally, I would like to propose that the
callback can modify both the key as well as the value by return an array
where the key would be used to replace the existing key and the value would
replace the existing value.
Currently, getting the key into the callback is only possible with
array_map by passing in a second array. Modifying both values (or applying
the return value of the callback to both the key and the value) is not
possible with array_map. Modifying the existing behavior of the function
would cause BC breaks since there are probably a lot of people using code
similar to the following:
array_map('strlen', array('foo','bar','baz','quix'));
Where strlen expects exactly one parameter and handing two arguments would
cause it to implicitly return null and issue an E_WARNING
with each
iteration of array_map.
To get both the key and the value into the callback you would have to do
something like the following:
array_map('my_callback', $array, array_keys($array));
Unfortunately, this has some performance and memory implications. PHP
arrays carry a lot of overhead and a large enough array means we hand a
copy of they array keys as an array to the function. This may be
unnecessary with a slightly improved implementation.
So instead we would have to have a new function like array_map_key
(perhaps) that passes two arguments to the callback on each iteration (the
key and the value of each element).
This would make the following code possible...
function my_call_back($key, $value) {
return array($value, strlen($value));
}
$array = str_word_count("PHP is lots of fun!");
$array = array_map_key('my_call_back', $array);
The result would be the following array:
array(5) {
["PHP"]=>
int(3)
["is"]=>
int(2)
["lots"]=>
int(4)
["of"]=>
int(2)
["fun"]=>
int(3)
}
This demonstrates modifying both the key as well as the value by applying a
user supplied callback function to each of the array's elements.
This can also be done with the foreach construct, but the problem with
foreach constructs is that they are not reusable. Since array_map takes a
callback it's easy to reuse the callback function in various places to
modify similar data structures. This is not so with foreach. It can be
argued that we simply put the foreach loop into a function and reuse that,
but there is a slight performance optimization with the implementation of
array_map that foreach can't do and that's that array_map can iterate over
all of the arrays supplied at once and more quickly than user space can do
the iteration.
It wouldn't be too hard to modify the implementation of array_map (
http://lxr.php.net/xref/PHP_5_5/ext/standard/array.c#4270) to pass in the
key and be able to return a new array where both key/value pairs are
applied by the callback given the existing implementation already accesses
this information with each iteration (so there's no noticeable performance
degradation). The only change would be in constructing the new return value
to include the key from the return value instead of using the existing key.
I would like to get everyone's thoughts on introducing such a function into
PHP 5.NEXT (obviously I'm too late for 5.5). If there is a real need for
this function out there and I'm not the only one that thinks this is useful
I would be happy to draft an RFC and provide an implementation.
Regards,
Sherif
I don't just make coffee around the office. Sometimes they let me write
code!
function my_call_back($key, $value) {
return array($value, strlen($value));
}
$array = str_word_count("PHP is lots of fun!");
$array = array_map_key('my_call_back', $array);The result would be the following array:
array(5) {
["PHP"]=>
int(3)
["is"]=>
int(2)
["lots"]=>
int(4)
["of"]=>
int(2)
["fun"]=>
int(3)
}
This example doesn't make any sense, as str_word_count returns an integer,
so you would in fact pass an int to array_map_key and not an array.
But let's say using your example, you use explode(" ", $string) instead of
str_word_count, which will give you an array of all the words.
What happens in the following case:
function my_call_back($key, $value) {
return array($value, strlen($value));
}
$array = str_word_count("PHP stands for PHP hypertext preprocessor");
$array = array_map_key('my_call_back', $array);
This would give you 2 keys with the value of PHP. What happens in this case?
What if you have duplicate integer keys. Does the keys simply increment or
throw an error?
On Sat, Jun 8, 2013 at 3:13 AM, Pierre du Plessis pierre@pcservice.co.zawrote:
function my_call_back($key, $value) {
return array($value, strlen($value));
}
$array = str_word_count("PHP is lots of fun!");
$array = array_map_key('my_call_back', $array);The result would be the following array:
array(5) {
["PHP"]=>
int(3)
["is"]=>
int(2)
["lots"]=>
int(4)
["of"]=>
int(2)
["fun"]=>
int(3)
}This example doesn't make any sense, as str_word_count returns an
integer, so you would in fact pass an int to array_map_key and not an array.
My mistake, I left out the second argument to str_word_count, which should
have been 1. In that case str_word_count would return an array of all the
words in supplied string.
But let's say using your example, you use explode(" ", $string) instead of
str_word_count, which will give you an array of all the words.What happens in the following case:
function my_call_back($key, $value) {
return array($value, strlen($value));
}
$array = str_word_count("PHP stands for PHP hypertext preprocessor");$array = array_map_key('my_call_back', $array);
This would give you 2 keys with the value of PHP. What happens in this
case?
What if you have duplicate integer keys. Does the keys simply increment or
throw an error?
The same thing that would happen if you did $array['PHP'] = 3;
$array['PHP'] = 3; The value would be overridden.
array_map_key would behave no differently than foreach would in this
matter. The code would semantically equivalent to the following:
function array_map_key(Callable $callback, $array) {
$return = array();
foreach ($array as $key => $value) {
list($k,$v) = $callback($key, $value);
$return[$k] = $v;
}
return $return;
}
You can see the PHP user-land implementation here with your
described example and the resulting output http://3v4l.org/pe855