<?
function my_array_map() {
$args = func_get_args();
$arr = array_shift($args);
foreach ($args as $fn) {
$nfn = create_function('&$v, $k, $fn', '$v = $fn($v);');
array_walk_recursive($arr, $nfn, $fn);
}
return $arr;
}
?>
takes an array as the first argument, and functions as the other arguments. it applies those functions recursively to the array
array_walk_recursive
(PHP 5)
array_walk_recursive — 对数组中的每个成员递归地应用用户函数
说明
bool array_walk_recursive
( array &$input
, callback $funcname
[, mixed $userdata
] )
将用户自定义函数 funcname 应用到 array 数组中的每个单元。本函数会递归到更深层的数组中去。典型情况下 funcname 接受两个参数。input 参数的值作为第一个,键名作为第二个。如果提供了可选参数 userdata ,将被作为第三个参数传递给 callback funcname 。
如果成功则返回 TRUE,失败则返回 FALSE。
Note: 如果 funcname 需要直接作用于数组中的值,则给 funcname 的第一个参数指定为引用。这样任何对这些单元的改变也将会改变原始数组本身。
Example#1 array_walk_recursive() 例子
<?php
$sweet = array('a' => 'apple', 'b' => 'banana');
$fruits = array('sweet' => $sweet, 'sour' => 'lemon');
function test_print($item, $key)
{
echo "$key holds $item\n";
}
array_walk_recursive($fruits, 'test_print');
?>
上例将输出:
a holds apple b holds banana sour holds lemon
注意上例中的键 'sweet' 并没有显示出来。任何其值为数组的键都不会被传递到回调函数中去。
参见 array_walk() 和有关 callback 类型的信息。
array_walk_recursive
amoffat at amoffat dot com
05-Jun-2008 08:15
05-Jun-2008 08:15
JW
15-Mar-2008 09:59
15-Mar-2008 09:59
This function has a serious bug, which is still not fixed as of the PHP 5.2.5 release. After you call it, it can accidentally modify your original array. Save yourself hours of frustration by reading on.
The bug is here: http://bugs.php.net/bug.php?id=42850, and it looks like it will be fixed for 5.3.
If the array that you walk contains other array elements, they will be turned into references. This will happen even if the callback function doesn't take its first argument by reference, and doesn't do anything to the values.
For example, try this:
<?php
$data = array ('key1' => 'val1', 'key2' => array('key3' => 'val3'));
function foo($item, $key){}
var_dump($data);
?>
The original array has no references. Now try this:
<?php
array_walk_recursive($data,'foo');
var_dump($data);
?>
Now key2 is a reference, not just an array. So if you do this:
<?php
function test($item){$item['key2'] = array();}
test($data);
var_dump($data);
?>
you will see that test modifies $data, even though it shouldn't.
One workaround is to immediately make a deep copy of the array after calling array_walk_recursive, like this:
<?php
function array_duplicate($input) {
if (!is_array($input)) return $input;
$output = array();
foreach ($input as $key => $value) {
$output[$key] = array_duplicate($value);
}
return $output;
}
array_walk_recursive($data,'foo');
$data = array_duplicate($data);
var_dump($data);
?>
After doing that, the references are gone.
wileur at gmail dot com
06-Mar-2007 09:59
06-Mar-2007 09:59
A simple way to use callback functions that are defined in a class is to simply pass the class instance and function names as values in an array:
<?php
class testClass {
function callbackFunction($value, $key) {
echo "$key: $value<br />\n";
}
function printArray($foo) {
array_walk_recursive($foo, array($this, 'callbackFunction'));
}
}
?>
adam dott pub att adamswick dott com
10-Nov-2006 10:08
10-Nov-2006 10:08
Thanks to all of you in the prior posts.
I don't like the fact that the current version of array_walk_recursive() doesn't track all array keys. This version will do that, as well as tracking array depth on multi-dimensional arrays.
- - - - - - -
Class Array_walk_recursive3 {
private $depth = -1;
private $userdata, $funcname;
public $status;
public $input;
public function __construct($input, $funcname, $userdata = "") {
$this->input = $input;
$this->funcname = $funcname;
$this->userdata = $userdata;
$this->status = $this->array_walk_recursive($this->input);
}
private function test_print(&$value, &$key)
{
echo str_repeat(" ", $this->depth)."$key holds ";
if (!is_array($value)) {
echo $value;
if (trim($value) == "banana") {
$value = "cherry";
$key = "c";
}
}
echo "\n";
}
private function array_walk_recursive(&$input) {
$funcname = array(&$this, $this->funcname);
if (!is_callable($funcname)) {
return false;
}
if (!is_array($input)) {
return false;
}
$this->depth++;
foreach (array_keys($input) AS $keyIdx => $key) {
$saved_value = $input[$key];
$saved_key = $key;
call_user_func_array($funcname, array(&$input[$saved_key], &$key));
if ($input[$saved_key] !== $saved_value || $saved_key !== $key) {
$saved_value = $input[$saved_key];
unset($input[$saved_key]);
$input[$key] = $saved_value;
}
if (is_array($input[$key])) {
if (!$this->array_walk_recursive($input[$key], $funcname)) return false;
$this->depth--;
}
}
return true;
}
}
$sweet = array('a' => 'apple', 'b' => 'banana');
$fruits = array('sweet' => $sweet, 'sour' => 'lemon');
$fruitObj = new Array_walk_recursive3($fruits, 'test_print');
echo $fruitObj->status;
$newFruitArr = $fruitObj->input;
print_r($fruits);
print_r($newFruitArr);
ik at paulkaspers dot nl
16-Oct-2006 04:46
16-Oct-2006 04:46
To egingell at sisna dot com:
There is a small bug in your function, the following line should be changed:
From: if ($value != $saved_value || $saved_key != $key) {
Into: if ($value !== $saved_value || $saved_key !== $key) {
It's a nice function, because I was searching for something to change the keys of a multiple dimension array.
gieterke at gmail dot com
29-Mar-2006 08:59
29-Mar-2006 08:59
I think there are a lot of people who want/have to work object oriented.
this is an Object oriented version
the code is written in PHP5
<?php
//auto overload classes, so you don't have to put in all the includes
function __autoload($class_name) {
require_once $class_name . '.php';
}
echo "TESTING: arraywalker<br>";
$anObject = new ClassName();
//array_walk_recursive($anObject->getFruits(), 'test_print'); => doesn't work
array_walk_recursive($anObject->getFruits(), array(&$anObject, 'test_print'));
echo"<br><br>";
//if you just want to give the array and not hte function name that handles the array
$anObject->arrWalker($anObject->getFruits());
?>
<?php
//Class description---------------------------------------------
class ClassName {
//Class variables
private $sweet = array();
private $fruits = array();
//Constructor
public function __construct(){
$this->sweet = array('a' => 'apple', 'b' => 'banana');
$this->fruits = array('sweet' => $this->sweet, 'sour' => 'lemon');
}
//public methods
public function getFruits(){
return $this->fruits;
}
public function test_print($item, $key){
echo "$key holds $item\n<br>";
}
public function arrWalker($arr){
array_walk_recursive($arr, array(&$this, 'test_print'));
}
}
?>
the code above gives following input:
TESTING: arraywalker
a holds apple
b holds banana
sour holds lemon
a holds apple
b holds banana
sour holds lemon
egingell at sisna dot com
18-Mar-2006 05:53
18-Mar-2006 05:53
Slightly modified version of array_walk_recursive function by "omega13a at sbcglobal dot net"
$function also modifies the keys in addition to the values.
Usefull if you want to trim() the keys and values of an array.
The $key in $funcname would also have to be passed by referrence.
Named 'array_walk_recursive2' since it is not the same as the PHP5 version, you can rename it to 'array_walk_recursive' if you are running PHP4 and have no reason to upgrade.
<?
function funcname(&$value, &$key, $userdata = "") {
// Do stuff to $value and $key
}
function array_walk_recursive2(&$input, $funcname, $userdata = "") {
if (!is_callable($funcname)) {
return false;
}
if (!is_array($input)) {
return false;
}
foreach ($input AS $key => $value) {
if (is_array($input[$key])) {
array_walk_recursive2($input[$key], $funcname, $userdata);
} else {
$saved_value = $value;
$saved_key = $key;
if (!empty($userdata)) {
$funcname($value, $key, $userdata);
} else {
$funcname($value, $key);
}
if ($value != $saved_value || $saved_key != $key) {
unset($input[$saved_key]);
$input[$key] = $value;
}
}
}
return true;
}
?>
gabrielu at hotmail dot com
22-Feb-2006 05:13
22-Feb-2006 05:13
I decided to add to the previous PHP 4 compatible version of array_walk_recursive() so that it would work within a class and as a standalone function. Both instances are handled by the following function which I modified from omega13a at sbcglobal dot net.
The following example is for usage within a class. To use as a standalone function take it out of the class and rename it. (Example: array_walk_recursive_2)
<?php
class A_Class {
function array_walk_recursive(&$input, $funcname, $userdata = '') {
if(!function_exists('array_walk_recursive')) {
if(!is_callable($funcname))
return false;
if(!is_array($input))
return false;
foreach($input as $key=>$value) {
if(is_array($input[$key])) {
if(isset($this)) {
eval('$this->' . __FUNCTION__ . '($input[$key], $funcname, $userdata);');
} else {
if(@get_class($this))
eval(get_class() . '::' . __FUNCTION__ . '($input[$key], $funcname, $userdata);');
else
eval(__FUNCTION__ . '($input[$key], $funcname, $userdata);');
}
} else {
$saved_value = $value;
if(is_array($funcname)) {
$f = '';
for($a=0; $a<count($funcname); $a++)
if(is_object($funcname[$a])) {
$f .= get_class($funcname[$a]);
} else {
if($a > 0)
$f .= '::';
$f .= $funcname[$a];
}
$f .= '($value, $key' . (!empty($userdata) ? ', $userdata' : '') . ');';
eval($f);
} else {
if(!empty($userdata))
$funcname($value, $key, $userdata);
else
$funcname($value, $key);
}
if($value != $saved_value)
$input[$key] = $value;
}
}
return true;
} else {
array_walk_recursive($input, $funcname, $userdata);
}
}
function kv_addslashes(&$v, $k) {
$v = addslashes($v);
}
}
?>
Usage:
<?php
$arr = array(
'a' => '"Hello World"',
'b' => "'Hello World'",
'c' => "Hello 'Worl\"d",
'd' => array(
'A' => 'H"e"l"l"o" "W"o"r"l"d'
)
);
$class = new A_Class();
$class->array_walk_recursive($arr, array(&$class, 'kv_addslashes'));
print_r($arr);
?>
omega13a at sbcglobal dot net
22-Dec-2005 08:21
22-Dec-2005 08:21
This is a peice of code I wrote that appears to create this function for PHP 4.
<?php
if (!function_exists('array_walk_recursive'))
{
function array_walk_recursive(&$input, $funcname, $userdata = "")
{
if (!is_callable($funcname))
{
return false;
}
if (!is_array($input))
{
return false;
}
foreach ($input AS $key => $value)
{
if (is_array($input[$key]))
{
array_walk_recursive($input[$key], $funcname, $userdata);
}
else
{
$saved_value = $value;
if (!empty($userdata))
{
$funcname($value, $key, $userdata);
}
else
{
$funcname($value, $key);
}
if ($value != $saved_value)
{
$input[$key] = $value;
}
}
}
return true;
}
}
?>
Please note it is a conditionaly set function and will have to be put before any call to it.
If there is anything wrong with it, please email me.
cory at lavacube dot com
07-Dec-2005 06:09
07-Dec-2005 06:09
A simple way to implement array_walk_recursive() in PHP 4 is to use to do the following...
<?php
// first, lets define our function
function test_array_walkr( &$item, $key )
{
// do what you want to do here - in this example we will
// check to see if $item is an array. If it is, we will
// check to see if the key '.hide' exists. If this exists,
// we will set the entire array to NULL;
if( is_array($item) && array_key_exists('.hide', $item) )
{
$item = NULL;
}
// this is the code that causes the recursive effect
// we do this after, to allow for any changes to $item
// to be included in the next recursive call...
if( is_array($item) )
{
array_walk($item, __FUNCTION__);
}
}
// next, let's define our array:
$test = array(
'one' => array('one->one', 'one->two', 'one->three'),
'two' => array('.hide'=>true, 'two->one', 'two->two', 'two->three'),
'three' => array('three->one', 'three->two', 'three->three')
);
// lets run the test. ;-)
array_walk($test, 'test_array_walkr');
// ... and get the results
print_r($test);
?>
This example will yeild:
Array
(
[one] => Array
(
[0] => one->one
[1] => one->two
[2] => one->three
)
[two] =>
[three] => Array
(
[0] => three->one
[1] => three->two
[2] => three->three
)
)
Hope this helps someone. :-)
aidan at php dot net
22-Feb-2005 03:10
22-Feb-2005 03:10
This functionality is now implemented in the PEAR package PHP_Compat.
More information about using this function without upgrading your version of PHP can be found on the below link:
http://pear.php.net/package/PHP_Compat
hannes (at) tismer.com
15-Dec-2004 03:08
15-Dec-2004 03:08
I wondered about an array_mergedown function working with PHP4, using an array_walk_recursive-like function which just merges any number of arrays of any dimension to a one dimension array containing every key=>value part of all arrays:
<?php
function array_mergedown() {
global $outarray;
$outarray = array();
function array_walk_recphp4(&$val,$key) {
global $outarray;
if (is_array($val)) array_walk($val,'array_walk_recphp4');
else {
$outarray[$key] = $val;
}
}
$params = func_get_args();
foreach ($params as $subarr) {
array_walk_recphp4($subarr, '');
}
return $outarray;
}
?>
For testing:
<?php
$arr1[]["foo1"] = "bar1";
$arr2["foo2"] = "bar2";
$arr2[12] = "bar3";
$arr2[10]["foo4"] = "bar4";
$arr2[]["foo4"][0]["foo5"] = "bar5";
$arr3 = "nono";
print_r(array_mergedown($arr1, $arr2, $arr3));
?>
returns:
Array ( [foo1] => bar1 [foo2] => bar2 [12] => bar3 [foo4] => bar4 [foo5] => bar5 )
I hope this helped someone :)
