Matt Welander
Matt Welander

Reputation: 8548

how to iterate over JSON property not knowing if it's array or not?

I have this problem where an API responds to me with DEPARTURESEGMENT sometimes containing only one object, and sometimes containing an array of objects. Depending on which case it is, I seem to need different logics in my foreach-loop.

Response A:

{
  "getdeparturesresult":{
     "departuresegment":[{
        "departure":{
           "location":{
              "@id":"7461018",
              "@x":"12.523958",
              "@y":"57.938402",
              "name":"Noltorps centrum"
           },
           "datetime":"2014-12-04 23:05"
        },
        "direction":"Alingsås station",
        "segmentid":{
           "mot":{
              "@displaytype":"B",
              "@type":"BLT",
              "#text":"Buss"
           },
           "carrier":{
              "name":"Västtrafik",
              "url":"http://www.vasttrafik.se/",
              "id":"279",
              "number":"1"
           }
        }
     },
     {
        "departure":{
           "location":{
              "@id":"7461018",
              "@x":"12.523958",
              "@y":"57.938402",
              "name":"Noltorps centrum"
           },
           "datetime":"2014-12-04 23:05"
        },
        "direction":"Alingsås station",
        "segmentid":{
           "mot":{
              "@displaytype":"B",
              "@type":"BLT",
              "#text":"Buss"
           },
           "carrier":{
              "name":"Västtrafik",
              "url":"http://www.vasttrafik.se/",
              "id":"279",
              "number":"1"
           }
        }
     }
     ]
  }
}

Works with this loop:

foreach ($apiData->getdeparturesresult->departuresegment as $m) {

While this response B:

{
  "getdeparturesresult":{
     "departuresegment":{
        "departure":{
           "location":{
              "@id":"7461018",
              "@x":"12.523958",
              "@y":"57.938402",
              "name":"Noltorps centrum"
           },
           "datetime":"2014-12-04 23:05"
        },
        "direction":"Alingsås station",
        "segmentid":{
           "mot":{
              "@displaytype":"B",
              "@type":"BLT",
              "#text":"Buss"
           },
           "carrier":{
              "name":"Västtrafik",
              "url":"http://www.vasttrafik.se/",
              "id":"279",
              "number":"1"
           }
        }
     }
  }
}

needs a loop like this (otherwise it throws an error):

foreach ($apiData->getdeparturesresult as $m) {

Is there a way to write the loop failsafe for whether DEPARTURESEGMENT is an array of objects or just one object (the brackets [] is the only difference to the structure of the json right?) or do I have to somehow test and see first whether DEPARTURESEGMENT is an array or not, and dispatch to two different loops depending on the outcome?

Upvotes: 1

Views: 104

Answers (3)

georg
georg

Reputation: 214969

I have this little useful function in my standard repertoire:

function iter($x) {
    if(is_array($x))
        return $x;
    if(is_object($x)) {
        if($x instanceof \Iterator)
            return $x;
        if(method_exists($x, 'getIterator'))
            return $x->getIterator();
        return get_object_vars($x);
    }
    return array($x);
}

This way you can use any variable with foreach without having to check it beforehand:

 foreach(iter($whatever) as $item)
    ...

Upvotes: 1

Vlad Preda
Vlad Preda

Reputation: 9910

You have a few methods that can help you:

In you situation, you would probably be fine by doing the following:

if (is_object($entry)) {
    handleObject($entry);
} elseif (is_array($entry) && count($entry)) {
    foreach ($entry as $e) {
        handleObject($e);
    }
}

Upvotes: 1

Pankucins
Pankucins

Reputation: 1720

How about checking whether it's an array or not with is_array? I made a simple example of it's usage here - http://codepad.org/WNjbIPZF

Upvotes: 0

Related Questions