2

I am trying to use recursion to loop through a multidimensional object, displaying a key value pair if the value is not an object, or invoking the same function from within if the value is a nested object. Here is my code:

<?php
function display_fields($data,$html='')
{
    foreach($data as $key => $value)
    {
        if (is_object($value)) $html .= display_fields($value,$html);
        else $html .= '
            <div class="row">
                <div class="col-xs-3">'.$key.'</div>
                <div class="col-xs-9">'.$value.'</div>
            </div>';
    }
    return $html;
}

This function would then initially be invoked passing the full object though.

I realise there might be better ways to do this, but I am particularly trying to learn about recursion, and would appreciate the chance to find out what I've done wrong here.

EDIT: I forgot to mention, the undesired outcome I'm getting is that the same data are getting repeated many, many times. So an object with 20 total properties might produce thousands of lines of results.

5
  • Is your code not working the way it is supposed to work ? Commented Jul 7, 2015 at 13:31
  • Just edited my question. Commented Jul 7, 2015 at 13:33
  • 1
    Can you post your array structure its better to look it that way Commented Jul 7, 2015 at 13:35
  • 1
    Why are you using $this-> in your function? ($this->display_fields) Could you please post your whole code with an example object? Commented Jul 7, 2015 at 13:36
  • I've removed the $this-> as it's arbitrary in this case. Commented Jul 7, 2015 at 13:45

2 Answers 2

5

As I understand your question, you only need call function without concating $html parameter with returned result:

function display_fields($data, &$html='') // added pass by reference
{
    foreach($data as $key => $value)
    {
        if (is_object($value)) 
            display_fields($value,$html); // no need to concat
        else $html .= '
            <div class="row">
                <div class="col-xs-3">'.$key.'</div>
                <div class="col-xs-9">'.$value.'</div>
            </div>';
    }
    return $html;
}
Sign up to request clarification or add additional context in comments.

2 Comments

I found that $html parameter must be passed by reference for it to work correctly, so I've edited to show this.
Oh, sorry, you are true!
3

This is a version that doesn't use pass-by-ref and has a minor amount of argument validation.

function display_fields($data)
{
    $html = '';

    if(is_object($data) || is_array($data)) {
        foreach($data as $key => $value)
        {
            if (is_object($value) || is_array($data)) { 
                $html .= display_fields($value);
            } else {
                $html .= '<div class="row">
                    <div class="col-xs-3">' . $key . '</div>
                    <div class="col-xs-9">' . $value . '</div>
                </div>';
            }
        }
    } else {
        throw new InvalidArgumentException('An object or array was expected.');
    }

    return $html;
}

And for another 'interesting' variant that tracks the full key path

function display_fields($data, $path = '')
{
    $html = '';

    if(is_object($data) || is_array($data)) {
        foreach($data as $key => $value)
        {
            if (is_object($value) || is_array($data)) { 
                $html .= display_fields($value, $path . $key . '.');
            } else {
                $html .= '<div class="row">
                    <div class="col-xs-3">' . $path . $key . '</div>
                    <div class="col-xs-9">' . $value . '</div>
                </div>';
            }
        }
    } else {
        throw new InvalidArgumentException('An object or array was expected.');
    }

    return $html;
}

3 Comments

Your second example is precisely something I could use atm. $path appears to never being set?
It's not set on the first call, but nested calls do set it.
ahh yes, thanks I can see now that $path is either empty, just the $key or $path . $key . Tired eyes, thanks for the help

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.