rfc:json_numeric_as_string

This is an old revision of the document!


PHP RFC: JSON numeric as string

Introduction

JSON is a data format that is often used for data exchange between different platforms. These platforms can have different number representation which might lead to problems like type inconsistency or precision loss.

Proposal

The proposal introduces new options for dealing with the number conversion problem by converting data to string.

Float to string conversion

The first option called JSON_FLOAT_AS_STRING converts all float values to string.

Decoding

The idea is to convert all float values to string when decoding JSON string. That prevents of precision loss.

Example
$data = json_decode('[1.23343224234, 1.34]', true, 512, JSON_FLOAT_AS_STRING);
var_dump($data);

outputs

array(2) {
  [0] =>
  string(13) "1.23343224234"
  [1] =>
  string(4) "1.34"
}
Use case

The use case is preventing precision loss. Currently the float precision is always lost due to C double conversion from string. This is even bigger problem if the user operates with very large numbers.

Encoding

The idea is to convert all float values to string when encoding PHP value.

Example
ini_set('precision', 12);
echo json_encode(arrray("a" => 1.23343224234, JSON_FLOAT_AS_STRING);

outputs

{"a":"1.23343224234"}
Use case

This might be useful when data are exported and then parsed by a parser that can't prevent of precision loss. That might be useful especially for platforms using C float type.

Integer to string conversion

The second option called JSON_INT_AS_STRING converts all int values to string.

Decoding

The idea is to convert all int values to string when decoding JSON string.

Example
$data = json_decode('[23343224234, 34]', true, 512, JSON_INT_AS_STRING);
var_dump($data);

will output:

array(2) {
  [0] =>
  string(11) "23343224234"
  [1] =>
  string(2) "34"
}
Use case

This decoding option might be useful when type consistency is required. The problem with precision is already resolved by JSON_BIGINT_AS_STRING. However when the numbers are on the edge of INT_MAX, then the result is combination of strings and integers.

Encoding

The idea is to convert all int values to string when encoding PHP value.

Example
echo json_encode(array( "a"=>123343224234), JSON_INT_AS_STRING);

will output

{"a":"123343224234"}
Use case

This encoding options might be useful when exporting integers greater than 1 << 31 from 64bit platforms to 32bit platforms and the target JSON parser cannot handle integer overflow.

Backward Incompatible Changes

The code that defines JSON_FLOAT_AS_STRING and/or JSON_INT_AS_STRING will be broken. However the constants have JSON_ prefix so their usage is not recommended and it should be relatively safe addition.

Proposed PHP Version(s)

The proposed versions will be one of the voting options as some might consider it as not a self-contained feature.

There will be choice of 3 PHP version.

  1. 5.6.next : this voting option considers the feature/bug as a self-contained small addition. The precedence for this is an addition of JSON_PRESERVE_ZERO_FRACTION that was added in 5.6 cycle.
  2. 7.0: this voting option considers the feature/bug as a self-contained but it does not consider feature important for 5.6. It will be up to Release Manager to decide whether to merge it to 7.0.0 or 7.0.1.
  3. 7.1: this option will consider the feature/bug as a non self-contained addition

New Constants

JSON_FLOAT_AS_STRING

  • json_decode - all float values are decoded as string
  • json_encode - all float values are encoded as string

JSON_INT_AS_STRING

  • json_decode - all int values are decoded as string
  • json_encode - all int values are encoded as string

Drawbacks

It is important to note that the number of JSON options is limited to 31 values. There is still space for adding new ones as currently 11 options are used and the future ones can be duplicated for decoding and encoding. However any new addition constant should be properly considered.

In addition, this proposal is not flexible as it has influence on all values of the affected type. That might be unwanted behavior especially for JSON_INT_AS_STRING. The only supported resulted type is a string which is another inflexibility.

Future replacement

As noted in the Drawbacks section, this proposal is not flexible. There could be a better solution. That solution could be implementation of Json Schema that would address all drawbacks. However its introduction is only possible in the next minor version and the time for the implementation is considerably bigger.

Unaffected PHP Functionality

This RFC is related only to JSON extension.

Voting Choices

50%+1 majority (see voting) for all votings

JSON_FLOAT_TO_STRING for decoding

Include JSON_FLOAT_TO_STRING for decoding?
Real name Yes No
derick (derick)  
ircmaxell (ircmaxell)  
kalle (kalle)  
mikemike (mikemike)  
remi (remi)  
yohgaki (yohgaki)  
Count: 1 5

JSON_FLOAT_TO_STRING for encoding

Include JSON_FLOAT_TO_STRING for encoding?
Real name Yes No
derick (derick)  
ircmaxell (ircmaxell)  
kalle (kalle)  
mikemike (mikemike)  
remi (remi)  
yohgaki (yohgaki)  
Count: 1 5

JSON_INT_TO_STRING for decoding

Include JSON_INT_TO_STRING for decoding?
Real name Yes No
derick (derick)  
ircmaxell (ircmaxell)  
kalle (kalle)  
mikemike (mikemike)  
remi (remi)  
yohgaki (yohgaki)  
Count: 1 5

JSON_INT_TO_STRING for encoding

Include JSON_INT_TO_STRING for encoding?
Real name Yes No
derick (derick)  
ircmaxell (ircmaxell)  
kalle (kalle)  
remi (remi)  
yohgaki (yohgaki)  
Count: 1 4

PHP version

This option applies only if one of the above votes has 50%+1 votes

PHP version used for the included constant
Real name PHP 5.6 PHP 7.0 PHP 7.1
derick (derick)   
ircmaxell (ircmaxell)   
kalle (kalle)   
mikemike (mikemike)   
remi (remi)   
yohgaki (yohgaki)   
Count: 1 0 5

Patches and Tests

The patch is really simple and will be implemented by the author of this RFC if accepted.

References

rfc/json_numeric_as_string.1433874026.txt.gz · Last modified: 2017/09/22 13:28 (external edit)