0

I am using a foreach construct to look at an array returned from a function. Unfortunately, this function returns different structures if there is only 1 result than if there are more than 1 result. When there is a single result, I get the following:

array(3) {
  ["name"]=>
  string(5) "chris"
  ["admin"]=>
  string(5) "chris"
  ["time"]=>
  string(19) "2014/06/27 12:36:31"
}
string(34) "$1$9243ujf0i2j8ehdf24hdf9a8"

I am trying to get the ["name"] value out. If I use the following code, my variable has the right data but I get an Illegal String Offset error:

foreach($res[1]['result']['user']['entry'] as $user) {
  $s = $user['name'];
  echo $s;
}

How do I properly get to the array["name"] value? Or do I have to do something different at a higher level? The raw data I get back is as follows when there is a single entry:

array(2) {
  ["@attributes"]=>
  array(2) {
    ["status"]=>
    string(7) "success"
    ["code"]=>
    string(2) "19"
  }
  ["result"]=>
  array(2) {
    ["@attributes"]=>
    array(2) {
      ["total-count"]=>
      string(1) "1"
      ["count"]=>
      string(1) "1"
    }
    ["user"]=>
    array(2) {
      ["@attributes"]=>
      array(2) {
        ["admin"]=>
        string(5) "chris"
        ["time"]=>
        string(19) "2014/06/27 12:39:58"
      }
      ["entry"]=>
      array(2) {
        ["@attributes"]=>
        array(3) {
          ["name"]=>
          string(5) "chris"
          ["admin"]=>
          string(5) "chris"
          ["time"]=>
          string(19) "2014/06/27 12:36:31"
        }
        ["phash"]=>
        string(34) "$1$9243ujf0i2j8ehdf24hdf9a8"
      }
    }
  }
}

and the following when there is more than one entry:

array(2) {
  ["@attributes"]=>
  array(2) {
    ["status"]=>
    string(7) "success"
    ["code"]=>
    string(2) "19"
  }
  ["result"]=>
  array(2) {
    ["@attributes"]=>
    array(2) {
      ["total-count"]=>
      string(1) "1"
      ["count"]=>
      string(1) "1"
    }
    ["user"]=>
    array(2) {
      ["@attributes"]=>
      array(2) {
        ["admin"]=>
        string(5) "chris"
        ["time"]=>
        string(19) "2014/06/27 12:57:32"
      }
      ["entry"]=>
      array(2) {
        [0]=>
        array(2) {
          ["@attributes"]=>
          array(3) {
            ["name"]=>
            string(5) "chris"
            ["admin"]=>
            string(5) "chris"
            ["time"]=>
            string(19) "2014/06/27 12:36:31"
          }
          ["phash"]=>
          string(34) "$1$9243ujf0i2j8ehdf24hdf9a8"
        }
        [1]=>
        array(2) {
          ["@attributes"]=>
          array(3) {
            ["name"]=>
            string(4) "test"
            ["admin"]=>
            string(5) "chris"
            ["time"]=>
            string(19) "2014/06/27 12:57:32"
          }
          ["phash"]=>
          string(34) "$1$as9d8jf238r9jf89j9238jr"
        }
      }
    }
  }
}

Note the extra indexed array level after ["entry"]. Basically, I just want the list of ["name"] values.

5
  • I'm pretty sure you want foreach($res[1]['result']['user']['entry']['@attributes'] as $user). Both of them hold the name bit inside that sub-array. Commented Jun 27, 2014 at 18:05
  • not really. Look at the structure again, the division is after entry. Commented Jun 27, 2014 at 18:16
  • @Anthony: Thanks, but that won't work. When there are more than one entry, there is an extra array level there: $res[1]['result']['user']['entry'][0]['@attributes']. When there is a single entry it's just $res[1]['result']['user']['entry']['@attributes']. Commented Jun 27, 2014 at 18:18
  • I totally missed the spot where the entry splits into an array. But there would be an illegal offset if you don't add @attributes to either path. Where does the array come from? Commented Jun 27, 2014 at 18:46
  • @Anthony: see my comment to this.lau_'s answer below. Commented Jun 27, 2014 at 19:10

3 Answers 3

1

The service that returns a different structure depending on the number of results is broken to begin with. If it cannot be fixed, you could try to normalize the data before processing it with something like this:

if (!isset($res[1]['result']['user']['entry'][1]) {
    // Not an array, so change the structure to an array with one element:
    $res[1]['result']['user']['entry'] = array($res[1]['result']['user']['entry']);
}

// Now process the data as if the service is always returning an array
Sign up to request clarification or add additional context in comments.

2 Comments

The source function that is returning the data is converting some XML to array by doing a $xml = simplexml_load_string, $json = json_encode($xml) and then $ret_array = json_decode($json, true). Not sure if I can fix this or if there is a better way to do it. Regardless, your answer worked great! Thanks.
Modifying the data to adjust to the code is not such a good idea in general, but it will "work".
1

You could normalize the entry array like so:

if(!isset($entries['result']['user']['entry'][0])) {
    $entry_list[] = $entries['result']['user']['entry'];
} else {
    $entry_list = $entries['result']['user']['entry'];
}

Then operate on the new $entry_list array with foreach without concern.

2 Comments

Thanks! This resulted in the simplest code I think.
it looks simpler, but it's the same effect as @this.lau_'s with the extra assignment to $entry_list
1

You can use is_array

$test = $res[1]['result']['user']['entry'];
if (is_array($test)) {
    foreach($test as $user) {
        $s = $user['@attributes']['name'];
        echo $s;
    }
} else {
    $s = $test['@attributes']['name'];
    echo $s;
}

3 Comments

That doesn't seem to work. is_array($test) evaluates true regardless of whether there is one entry or more. What I need to know I guess is if $res[1]['result']['user']['entry'][0] exists or does not exist.
Using your suggestion, I got the following to work: $test = $res[1]['result']['user']['entry']; if (is_array($test[0])) { foreach($test as $user) { echo $user['@attributes']['name']; } } else { echo $test['@attributes']['name']; }
I was just missing the ['@attributes'] part... but if you test for $test[0] instead of $test, you will get an error when it's a single value, because $test[0] will not exist.

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.