php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Request #46600 "_empty_" key in objects (see #41504)
Submitted: 2008-11-18 03:13 UTC Modified: 2016-06-23 19:15 UTC
Votes:10
Avg. Score:4.2 ± 0.7
Reproduced:10 of 10 (100.0%)
Same Version:4 (40.0%)
Same OS:6 (60.0%)
From: Matt at mpcm dot com Assigned: bukka (profile)
Status: Closed Package: JSON related
PHP Version: irrelevant OS: *
Private report: No CVE-ID: None
 [2008-11-18 03:13 UTC] Matt at mpcm dot com
Description:
------------
json_decode() treats empty property name as "_empty_" not "". This was fixed in #41504 for arrays, but not for objects. (seems to happen in PHP Version 5.2.4-2ubuntu5.3 and 5.3.0alpha2.

Reproduce code:
---------------
<?
$s = '{"":"test"}';
var_dump(json_decode($s));
?>


Expected result:
----------------
object(stdClass)#1 (1) { [""]=>  string(4) "test" }

Actual result:
--------------
object(stdClass)#2 (1) { ["_empty_"]=>  string(4) "test" }

Patches

Add a Patch

Pull Requests

Pull requests:

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2008-11-18 15:43 UTC] matt at mpcm dot com
All the work arounds I am looking at are throwing Error Text: Illegal member variable name when I convert/cast an object with a blank property.

Is this json_decode `bug` a result of a larger object mechanism limitation inside of php's object handling?
 [2008-11-18 17:35 UTC] matt at mpcm dot com
The language seems to create a key that cannot be reached, so even if this `bug` is fixed, we am still facing a broader issue it seems.

<?
$key = "";
$o = (object) array($key=>4,"example"=>8);
var_dump($o);
print 'blank key test:' . (isset($o->$key)?'true':'false');
print $o->{$key};
var_dump($o->$key);
?>

output:
object(stdClass)#1 (2) {
  [""]=>
  int(4)
  ["example"]=>
  int(8)
}
blank key test:false<br />
<b>Fatal error</b>:  Cannot access empty property in <b>PHPDocument1</b> on line <b>8</b><br />
All throws Notice: line 4 - Illegal member variable name
 [2008-12-04 10:44 UTC] magicaltux@php.net
I believe this is not a bug, but a feature.

An object *can't* have an empty property (while an array can).

If you want to use json_decode() with json containing empty key, either access those empty key using special keyword "_empty_", or put the optionnal $assoc parameter of json_decode() to true to get result as an array.

If you want objects to support empty keys, I believe this is not going to happen soon, as this is enforced by a specific error message.

Fatal error: Cannot access empty property in php shell code on line 1

Please note that a property name starting with NULL character won't work either.
 [2008-12-04 20:39 UTC] Matt at mpcm dot com
Thanx for the reply magicaltux, `Feature` is an interesting word considering the possible key collision.

There are other ways to get things that are not strictly objects to behave that way. Overloading (like example #1 at http://us.php.net/manual/en/language.oop5.overloading.php). It works well enough as long as you also make it iterate correctly.

What I am suggesting is that it is better to fail in decoding into an object, than to silently cause a key collision. 

Or alternatively, produce an overloaded object which can have these keys (by default, or passed optional flag) from json_decode. It's an opinion, but a wrapper gets me where I need to be for now, and I'm pretty sure this is an edge case.

$a = '{"":"a","_empty_":"b"}';
echo json_encode(json_decode($a)); 
echo json_encode(json_decode($a, true));

output:
{"_empty_":"b"}
{"":"a","_empty_":"b"}

for some values:
$a != json_encode(json_decode($a));
 [2008-12-18 03:27 UTC] scottmac@php.net
I'm not even sure what the bug is? You can't have an empty property name hence the use of "_empty_".

The key collision thing is a very edge case, are you saying you ran into this in a real life usage?

The best course of action may be to have this documented on the json_encode() and json_decode() pages.
 [2008-12-23 16:47 UTC] matt at mpcm dot com
A note about this in the json_decode page would be appreciated. Perhaps a strict mode flag, so that it can fail if it cannot be decoded as an object (?). For the moment the only safe way to decode json is into arrays.

The _empty_ behavior I thought was a bug (as it was with arrays) is a required behavior for objects (at least without __get && __set in a wrapper class).

The bugs that jump out at me now can be seen with the code below... you can create objects with unreachable properties. If that blank property access is fixed, then this becomes not so much of an issue. Or it should be stopped from ever happening... silent errors bite us all.

Illegal Member variable name if var_dump does it, fatal if a user does it.

Notice: PHPDocument1 line 8 - Illegal member variable name

<?
$blank = '';
$another = '   another';
$a = array($blank=>1234, 'some other key'=>5678, $another=>9999);
$b = (object) $a;
$c = json_decode(json_encode($a));

var_dump($b);
var_dump($c);

#echo $b->$blank;	//fatal
echo $b->$another;	//works
						
#echo $c->$blank;	//fatal
echo $c->$another;	//works

?>
 [2008-12-26 01:00 UTC] php-bugs at lists dot php dot net
No feedback was provided for this bug for over a week, so it is
being suspended automatically. If you are able to provide the
information that was originally requested, please do so and change
the status of the bug back to "Open".
 [2009-08-12 21:20 UTC] michaeldnelson dot mdn at gmail dot com
I am using freebsd 7.2 and php 5.2.10 the first test case
 
var_dump(json_decode('{"":"test"}'));

silently stops processing of the script

The test case

var_dump(json_decode('{"test2":5,"":6}'));

Fatal error: Cannot access empty property

I am not sure the second is expected behavior but considering json is often from feeds it would be nice to fail more gracefully.
 [2009-08-12 22:49 UTC] scottmac@php.net
Works for me here with 5.2-dev and 5.3-dev

object(stdClass)#1 (2) {
  ["test2"]=>
  int(5)
  ["_empty_"]=>
  int(6)
}

 [2014-01-14 18:47 UTC] matt at mpcm dot com
To illustrate the current collision state, as this came up on the JSMentors list recently.

<?php
$a = '{"_empty_":"a","":"b","":"c"}';
echo "as object: " . json_encode(json_decode($a));
echo "\n";
echo "as array: " . json_encode(json_decode($a, true));

PHP 5.4.17 (cli) (built: Aug 25 2013 02:03:38)
Copyright (c) 1997-2013 The PHP Group
Zend Engine v2.4.0, Copyright (c) 1998-2013 Zend Technologies
 [2014-01-14 18:48 UTC] matt at mpcm dot com
With an output of:
as object: {"_empty_":"c"}
as array: {"_empty_":"b","":"c"}
 [2014-01-14 18:50 UTC] matt at mpcm dot com
Last post was a bad example, this is the actual output:
as object: {"_empty_":"c"}
as array: {"_empty_":"a","":"c"}
 [2016-01-25 14:56 UTC] ajf@php.net
This is arguably not a bug since you can't have objects with empty property names, so this is necessary to allow decoding JSON objects with empty keys. However, that's a rather arbitrary restriction. If we removed it, we could fix this.
 [2016-03-23 02:49 UTC] ofbeaton at gmail dot com
So I just ran into this problem while making a satis repository script for composer. I don't see a good solution.

If I `$composerJson = json_decode($composerJson, true)` into associative arrays, manipulate it, then `json_encode($composerJson)` then my 
  "require-dev": {}
turns into
  "require-dev": []
which composer chokes on. So obviously I can't read the composer file as associative arrays! That isn't this bug, I just want to show upfront that using the associative array parameter on my json_decode cannot solve my problem.

So I do: `$composerJson = json_decode($composerJson, false)` and turn it into objects like this thread talks about. Except the most common composer.json contains something like this:
  "autoload": {
    "psr-4": {
      "": "src/"
    }
  }

it reads it in fine, but when I do `json_encode($composerJson)` again... I get:
  "autoload": {
    "psr-4": {
      "_empty_": "src/"
    }
  }

which composer then chokes on because of course "_empty_" has a different meaning than "".

So I'm stuck doing a json_encode then using a hack, `$composerJson = str_replace('"_empty_":', '"":', $composerJson)` before writing it to file again.

The _empty_ key does not seem to me to be the right answer here. Should composer change the way composer files for virtually all projects be written? Is this a composer bug?

Or should json_encode and json_decode objects reproduce a blank key?

I hope the answer is the later, but I cannot say for sure.
 [2016-03-23 07:43 UTC] yohgaki@php.net
Property names are defined as "string" and "string" is defined as follows.

https://tools.ietf.org/html/rfc7159#section-7

      string = quotation-mark *char quotation-mark

      char = unescaped /
          escape (
              %x22 /          ; "    quotation mark  U+0022
              %x5C /          ; \    reverse solidus U+005C
              %x2F /          ; /    solidus         U+002F
              %x62 /          ; b    backspace       U+0008
              %x66 /          ; f    form feed       U+000C
              %x6E /          ; n    line feed       U+000A
              %x72 /          ; r    carriage return U+000D
              %x74 /          ; t    tab             U+0009
              %x75 4HEXDIG )  ; uXXXX                U+XXXX

      escape = %x5C              ; \

      quotation-mark = %x22      ; "

      unescaped = %x20-21 / %x23-5B / %x5D-10FFFF


https://tools.ietf.org/html/rfc7159#section-4

Object property name should be unique. i.e. "The names within an object SHOULD be unique."

I cannot tell if "" is valid or not. Is it valid JSON?

BTW, the name for empty elements should be "__empty" or "__empty__" as we usually "__name" or "__name__" for reserved names.
 [2016-03-23 12:17 UTC] matt at mpcm dot com
Looking at that same doc:
https://tools.ietf.org/html/rfc7159#section-1

"A string is a sequence of zero or more Unicode characters [UNICODE]."
 [2016-03-23 22:36 UTC] yohgaki@php.net
-Status: No Feedback +Status: Re-Opened -PHP Version: 5CVS, 6CVS (2008-11-18) +PHP Version: irrelevant
 [2016-03-23 22:36 UTC] yohgaki@php.net
I fully agree empty string is valid unicode string.

The RFC does not mention validity of empty object property which is invalid in most languages. 

There is nothing we can do for this because object property name cannot be "". Any restrictions to property name apply as well for objects.

However, we can cast object to array, array to object.

[yohgaki@dev ~]$ php -n -r '$a = [""=>1]; $o = (object)$a; var_dump($o); $a = (array)$o; var_dump($a);'
object(stdClass)#1 (1) {
  [""]=>
  int(1)
}
array(1) {
  [""]=>
  int(1)
}

It may be better to remove automatic "" -> "_empty_" conversion at some point. e.g. next minor release.
 [2016-03-23 22:37 UTC] yohgaki@php.net
-Type: Bug +Type: Feature/Change Request
 [2016-03-25 03:38 UTC] matt at mpcm dot com
Yasuo, thank you for the response.

Blank keys in json are a relatively common thing to encounter.

I do agree, not all languages offer access to "", especially within traditional concept of a predefined class and named property.
But... it feels like PHP should be able to handle this. Since we already have `leading space` properties working...


I think the real fix (or feature request) for this bug, is that json_decode should not be returning stdClass at all.
But something that extends stdClass, with a __get/__set to handle non-valid property strings that are valid json keys.
Paired with undoing "" to "_empty_", this would essentially remove the issue entirely.

Maybe that add's even more complications to php that I'm not considering ?
Are there other keys that come to mind, or things that php also remaps, besides "" to "_empty_" ?


I'll take a look at the newer php constructs this weekend, to see if there is an easier way around this now.
I haven't looked into the issue recently, but in the past I used something like the below to allow object style access.
https://gist.github.com/mpcm/2ce3687b121fdd13e2a8#file-jsonobject-class-php-L2
 [2016-05-09 19:14 UTC] bukka@php.net
-Assigned To: +Assigned To: bukka
 [2016-05-09 19:14 UTC] bukka@php.net
Nikita has already sent a patch to allow empty property names in object. I will be happy to provide json part if that patch is merged.
 [2016-06-23 19:14 UTC] bukka@php.net
-Status: Re-Opened +Status: Closed
 [2016-06-23 19:15 UTC] bukka@php.net
The PR removing this limitation has been merged and an empty property name will be used instead.
 [2019-02-11 16:02 UTC] aleksey dot moskovchenko at gmail dot com
('_empty_' == 0  ) equal true,why?
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Tue Mar 19 02:01:28 2024 UTC