3

How can I return multidimensional array keys in tree format in PHP?

For example, if I have the following array:

$array = array ( 
    array (
        'name' => 'A', 
        'product' => array (
            'qty' => 1,
            'brand' => 'Tim'
        ), 
        'goods' => array (
            'qty' => 2
        ), 
        'brand' => 'Lin'
    ),
    array (
        'name' => 'B', 
        'product' => array (
            'qty' => 6,
            'brand' => 'Coff'
        ),
        'goods' => array (
            'qty' => 4
        ), 
        'brand' => 'Ji'
    )
);

How can I get a result like the following -- including no repeating of keys:

-name
-product
--qty
--brand
-goods
--qty
--brand
1
  • Hold on, you only want the keys printed, with no values? Commented Jun 28, 2012 at 11:20

3 Answers 3

1

Recursive functions should cover any depth you want/need:

 function print_tree($tree, $level = 0) {
     foreach($tree AS $name => $node) {
         if(
               is_scalar($node) OR
               (
                   is_object($node) AND
                   method_exists($node, '__toString')
               )
           ) {
             echo str_repeat('-', $level).$name.': '.$node;
         }
         else if(
                   is_array($node) OR
                   (
                       is_object($node) AND
                       $node InstanceOf Traversable
                   )
                ) {
             echo str_repeat('-', $level).$name.":\n";
             print_tree($node, $level+1);
         }
     }
 }
Sign up to request clarification or add additional context in comments.

8 Comments

Looks like you beat me to it. However, maybe you would want to print a string-representation of non-scalar values.
I added the extra checks for string-able objects and for array-able objects
Printing something like [object of class X] would be useful for objects with no __toString method. And resources. Iterator extends traversable, so that doesn't need to be included.
And AFAIK, objects which just implement ArrayAccess aren't traversable using foreach.
I thought Traversable is only used by internals. I don't agree that printing [object ClassName] is better first of all because we're not creating a print_r/var_dump analysis function, just a tree printer for circumstances when you have for example categories and such in a tree.
|
0

With an unlimited depth you need a recursive function. I suppose you have the parents in $names and the childs in $children:

function render_select($root=0, $level=-1) 
{
    global $names, $children;
    if ($root != 0)
       echo '<option>' . strrep(' ', $level) . $names[$root] . '</option>';
    foreach ($children[$root] as $child)
       render_select($child, $level+1);
}

This functions use useful because you can feed it with 2 variables. The other answere requires a multidimensional array.

6 Comments

Global variables in functions are bad design and bad practice. They rely on the names of variables in the global scope, and make your function un-portable. global and $GLOBALS are much like goto - just because they are there, doesn't mean you should ever use them. There are rare exceptions to the rule, but this is not one of them.
Typo3 uses a lot of global variables. Can you say constants are better then global variables?
Most problems "fixed" by functional programming languages and object oriented programming languages relate to encapsulating data and having a clear path of "where the data came from", "where it was modified last", "how was it modified". Procedural code had the downside that by using global and goto you can accidentally get the result of changing the global variables at moments when you expected them to keep their state. Hence the behavior of the application changes.
Constants are constant globals are global you don't compare apples to oranges.
Constants are different from variables, as they hold constant (never changing) scalar values. For a job like this, you want to pass the array to the function, and have a single argument that passes through the recursion to track the current depth.
|
0
function print_tree($array, $level=1) {
    foreach($array as $element) {
        if(is_array($element)) {
            print_tree($element, $level+1);
        } else {
            print str_repeat('-', $level).$element."\n";
        }
    }
}

4 Comments

You should first check if the value is_scalar because it is more likely for it to be a scalar and it takes less time to check if it's a scalar vs. testing if it's an array/object.
IMO, printing a string-representation of values that are non-array & non-scalar is more desirable than omitting them completely.
That's true but you can't print an object that doesn't have a __toString method can you? so you should check to make sure.
See my comments on your answer.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.