23

I'm experiencing odd behavior with json_encode after removing a numeric array key with unset. The following code should make the problem clear. I've run it from both the CLI and as an Apache mod:

PHP version info:

C:\Users\usr\Desktop>php -v
PHP 5.3.1 (cli) (built: Nov 20 2009 17:26:32)
Copyright (c) 1997-2009 The PHP Group
Zend Engine v2.3.0, Copyright (c) 1998-2009 Zend Technologies

PHP Code

<?php

$a = array(
    new stdclass,
    new stdclass,
    new stdclass
);
$a[0]->abc = '123';
$a[1]->jkl = '234';
$a[2]->nmo = '567';

printf("%s\n", json_encode($a));
unset($a[1]);
printf("%s\n", json_encode($a));

Program Output

C:\Users\usr\Desktop>php test.php
[{"abc":"123"},{"jkl":"234"},{"nmo":"567"}]
{"0":{"abc":"123"},"2":{"nmo":"567"}}

As you can see, the first time $a is converted to JSON it's encoded as a javascript array. The second time around (after the unset call) $a is encoded as a javascript object. Why is this and how can I prevent it?

Charles
  • 50,943
  • 13
  • 104
  • 142
leepowers
  • 37,828
  • 23
  • 98
  • 129

3 Answers3

21

The reason for that is that your array has a hole in it: it has the indices 0 and 2, but misses 1. JSON can't encode arrays with holes because the array syntax has no support for indices.

You can encode array_values($a) instead, which will return a reindexed array.

zneak
  • 134,922
  • 42
  • 253
  • 328
  • Alternatively you can sort the array after unsetting an element. – NullUserException Oct 06 '10 at 02:35
  • @NullUserException Though that will have the side effect of, well, sorting your array. – zneak Oct 06 '10 at 02:36
  • For those wondering about the `unset` behavior, view the following link and scroll down to "Useful functions": http://us3.php.net/manual/en/language.types.array.php "The unset() function allows removing keys from an array. Be aware that the array will not be reindexed" – leepowers Oct 06 '10 at 02:46
  • @NullUserException Great addition! Needed to sort the array anyway - killing two birds with one stone. – sjkm Dec 13 '16 at 10:41
7

In addition to the array_values technique it is possible to use array_splice and remove an element and re-index in one step:

unset($a[1]);

Instead:

array_splice($a, 1, 1);
leepowers
  • 37,828
  • 23
  • 98
  • 129
2

Try to use JSON_FORCE_OBJECT option for json_encode, like: json_encode($a, JSON_FORCE_OBJECT) so you will always have the same result.

barbushin
  • 5,165
  • 5
  • 37
  • 43