PHP Doku:: Wendet eine Benutzerfunktion rekursiv auf jedes Element eines Arrays an - function.array-walk-recursive.html

Verlauf / Chronik / History: (1) anzeigen

Sie sind hier:
Doku-StartseitePHP-HandbuchFunktionsreferenzVariablen- und typbezogene ErweiterungenArraysArray Funktionenarray_walk_recursive

Ein Service von Reinhard Neidl - Webprogrammierung.

Array Funktionen

<<array_values

array_walk>>

array_walk_recursive

(PHP 5)

array_walk_recursiveWendet eine Benutzerfunktion rekursiv auf jedes Element eines Arrays an

Beschreibung

bool array_walk_recursive ( array &$input , callback $funcname [, mixed $userdata ] )

Wendet die mittels funcname angegebene Benutzerfunktion für jedes Element von input an. Diese Funktion steigt tiefer in Arrays hinab. üblicherweise benötigt funcname zwei Parameter. Der Wert von input wird als erster übergeben, und der Schlüssel/Index als zweites. Ist der optionale Parameter userdata angegeben, so wird er als dritter Parameter an die Funktion funcname übergeben.

Gibt bei Erfolg TRUE zurück. Im Fehlerfall wird FALSE zurückgegeben.

Hinweis:

Falls funcname mit den tatsächlichen Werten des Arrays arbeiten muss, muss man den ersten Parameter von funcname als Reference übergeben. Dann werden alle Änderungen an den Elementen im ürsprünglichen Array selbst vorgenommen.

Beispiel #1 array_walk_recursive() Beispiel

<?php
$sweet 
= array('a' => 'Apfel''b' => 'Banane');
$fruits = array('süß' => $sweet'sauer' => 'Zitrone');

function 
test_print($item$key
{
    echo 
"$key beinhaltet $item\n";
}

array_walk_recursive($fruits'test_print');
?>

Das oben gezeigte Beispiel erzeugt folgende Ausgabe:

a beinhaltet Apfel
b beinhaltet Banane
sauer beinhaltet Zitrone

Sie werden bemerken, dass der Schlüssel 'süß' nicht angezeigt wird. Jeder Schlüssel, der ein array beinhaltet, wird nicht an die Funktion übergeben.

Siehe auch array_walk(), und Informationen über den Callback-Typ.


16 BenutzerBeiträge:
- Beiträge aktualisieren...
rob at yurkowski dot net
26.10.2010 20:16
If you don't really particularly care about the keys of an array, you can capture all values quite simply:

<?php

$sample
= array('dog' => 'woof', 'cat' => array('angry' => 'hiss', 'happy' => 'purr'), 'aardvark' => 'kssksskss');
$output = array();

// Push all $val onto $output.
array_walk_recursive($sample, create_function('$val, $key, $obj', 'array_push($obj, $val);'), &output);

// Printing
echo nl2br(print_r($output, true));

/*
* Array
* (
*  [0] => woof
*  [1] => hiss
*  [2] => purr
*  [3] => kssksskss
* )
*/
?>
bradbeattie at gmail dot com
27.08.2010 20:18
The description says "If funcname needs to be working with the actual values of the array, specify the first parameter of funcname as a reference." This isn't necessarily helpful as the function you're calling might be built in (e.g. trim or strip_tags). One option would be to create a version of these like so.

<?php
   
function trim_by_reference(&$string) {
       
$string = trim($string);
    }
?>

The downside to this approach is that you need to create a wrapper function for each function you might want to call. Instead, we can use PHP 5.3's inline function syntax to create a new version of array_walk_recursive.

<?php
   
/**
     * This function acts exactly like array_walk_recursive, except that it pretends that the function
     * its calling replaces the value with its result.
     *
     * @param $array The first value of the array will be passed into $function as the primary argument
     * @param $function The function to be called on each element in the array, recursively
     * @param $parameters An optional array of the additional parameters to be appeneded to the function
     *
     * Example usage to alter $array to get the second, third and fourth character from each value
     *     array_walk_recursive_referential($array, "substr", array("1","3"));
     */
   
function array_walk_recursive_referential(&$array, $function, $parameters = array()) {
       
$reference_function = function(&$value, $key, $userdata) {
           
$parameters = array_merge(array($value), $userdata[1]);
           
$value = call_user_func_array($userdata[0], $parameters);
        };
       
array_walk_recursive($array, $reference_function, array($function, $parameters));
    }
?>

The advantage here is that we only explicitly define one wrapper function instead of potentially dozens.
devel at starosta dot org
13.10.2008 2:41
Nice system to make DB tree using function array_walk_recursive:

<?php
function _CategoriesTree(&$item, $key)
{
global
$objDB;

  if (
$key=="childs")
  {
   
$res = $objDB->getAssoc('SELECT category_id, name,category_parent_id, category_id AS childs  FROM categories WHERE category_parent_id = '.$item.' ORDER BY orderid');
    if(!empty(
$res))
    {
     
// walk inside subcategories
     
$item = $res;
    }
    else
    {
     
// equvalent => no childs
     
$item = -1;
    }
  }
}

$categories = $objDB->getAssoc('SELECT category_id, name,category_parent_id, category_id AS childs  FROM categories WHERE category_parent_id = 0 ORDER BY orderid');  // fetchPairs -> value is the index
array_walk_recursive($categories, 'treeFunc',$objDB);

// test
print_r($categories);
?>
martin dot velek at gmail dot com
28.09.2008 23:01
If you will know that a tree in DB is not huge you can use array_walk_recursive to create tree structure e.g. in array.

let's assume following table:
NAME        PARENT
a                  null
b                  null
c                  null
a1               a
a2               a
b1               b
b11             b1
b111           b11

<?php
require_once 'Zend/Db/Adapter/Pdo/Sqlite.php';

function
treeFunc(&$item, $key, $dbConn)
{
   
$res = $dbConn->fetchPairs('SELECT name FROM tree where parent = ?',$key);
    if(!empty(
$res))
        
$item = $res;
}

$arr = $dbConn->fetchPairs('SELECT name FROM tree where parent is null');  // fetchPairs -> value is the index

$valid = true;
while(
$valid)
{
      
$oldCount  = count($arr,COUNT_RECURSIVE);
      
array_walk_recursive($arr, 'treeFunc',$dbConn);
      
$newCount = count($arr,COUNT_RECURSIVE);
       if (
$oldCount == $newCount// if there is no change, exit...
                  
$valid = false;    
}
print_r($arr);
?>

--------------------------------------------------
Array
(
    [a] => Array
        (
            [a1] =>
            [a2] =>
        )

    [b] => Array
        (
            [b1] => Array
                (
                    [b11] => Array
                        (
                            [b111] =>
                        )

                )

        )

    [c] =>
)
amoffat at amoffat dot com
5.06.2008 2:15
<?
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
JW
15.03.2008 2: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
6.03.2007 14: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.11.2006 3: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
15.10.2006 22: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.03.2006 14: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.03.2006 10: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
21.02.2006 22: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.12.2005 1: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
6.12.2005 23: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.02.2005 8: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
14.12.2004 20: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 :)



PHP Powered Diese Seite bei php.net
The PHP manual text and comments are covered by the Creative Commons Attribution 3.0 License © the PHP Documentation Group - Impressum - mail("TO:Reinhard Neidl",...)