Search code examples
phpjsonarray-filter

Why is json-rendered output from array_filter different to output from foreach?


I have stumbled across an obscure bug which took me a long time to fix and I am vaguely curious about the underlying cause. Could someone please shed some light on the anomaly that I'm seeing when using the array_filter function instead of a simple loop.

I would have thought the following two blocks of code would produce the same result:

// original 'buggy' version
$obj_to->ExtendedProperties[] = array_filter($extendedProperties, function($item){
  return isset($item);
});

// later, working version
foreach ($extendedProperties as $prop) {
  if (isset($prop)) $obj_to->ExtendedProperties[] = $prop;
}

However the API to which I was then sending the results did not consider their output equivalent and returned a 400 error. I've included samples of the different json output. In one case, we see an array indice in the printed json and in the other, we don't.

// 'good' json
"ExtendedProperties": [
  {
     "Name": "MaterialCode",
     "Value": "5450790E0LD048P8"
  },
...

as opposed to

// 'bad' json
"ExtendedProperties": {
  "0": {
      "Name": "PreferredDate",
      "Value": "2016-06-01"
  },
...

Solution

  • You get the "bad" json output because array_filter preserves the array keys from $extendedPropertiesArray.

    http://php.net/manual/en/function.array-filter.php#99358

    Because array_filter() preserves keys, you should consider the resulting array to be an associative array even if the original array had integer keys for there may be holes in your sequence of keys. This means that, for example, json_encode() will convert your result array into an object instead of an array. Call array_values() on the result array to guarantee json_encode() gives you an array.