Skip to content

Commit d9489d3

Browse files
authored
Merge pull request #86 from TysonAndre/fix-c-bindings
3.0.0: Throw errors/SimdJsonException in more cases to be consistent with json_decode, make C bindings usable by other PECLs
2 parents aec72eb + 222ad9a commit d9489d3

22 files changed

Lines changed: 551 additions & 271 deletions

README.md

Lines changed: 56 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -108,47 +108,75 @@ var_dump($res) //int(5)
108108
<?php
109109

110110
/**
111+
* Takes a JSON encoded string and converts it into a PHP variable.
111112
* Similar to json_decode()
112113
*
114+
* @param string $json The JSON string being decoded
115+
* @param bool $associative When true, JSON objects will be returned as associative arrays.
116+
* When false, JSON objects will be returned as objects.
117+
* @param int $depth the maximum nesting depth of the structure being decoded.
113118
* @return array|stdClass|string|float|int|bool|null
114119
* @throws SimdJsonException for invalid JSON
115-
* (or document over 4GB, or out of range integer/float)
120+
* (or $json over 4GB long, or out of range integer/float)
121+
* @throws SimdJsonValueError for invalid $depth
116122
*/
117-
function simdjson_decode(string $json, bool $assoc = false, int $depth = 512) {}
123+
function simdjson_decode(string $json, bool $associative = false, int $depth = 512) {}
118124

119125
/**
120126
* Returns true if json is valid.
121127
*
122-
* @return ?bool (null if depth is invalid)
128+
* @param string $json The JSON string being decoded
129+
* @param int $depth the maximum nesting depth of the structure being decoded.
130+
* @return bool
131+
* @throws SimdJsonValueError for invalid $depth
123132
*/
124-
function simdjson_is_valid(string $json, int $depth = 512) : ?bool {}
133+
function simdjson_is_valid(string $json, int $depth = 512) : bool {}
125134

126135
/**
127136
* Parses $json and returns the number of keys in $json matching the JSON pointer $key
128137
*
129-
* @return ?int (null if depth is invalid)
130-
* @throws SimdJsonException for invalid JSON
138+
* @param string $json The JSON string being decoded
139+
* @param string $key The JSON pointer being requested
140+
* @param int $depth The maximum nesting depth of the structure being decoded.
141+
* @param bool $throw_if_uncountable If true, then throw SimdJsonException instead of returning 0 for JSON pointers
142+
to values that are neither objects nor arrays.
143+
* @return int
144+
* @throws SimdJsonException for invalid JSON or invalid JSON pointer
131145
* (or document over 4GB, or out of range integer/float)
146+
* @throws SimdJsonValueError for invalid $depth
147+
* @see https://www.rfc-editor.org/rfc/rfc6901.html
132148
*/
133-
function simdjson_key_count(string $json, string $key, int $depth = 512) : ?int {}
149+
function simdjson_key_count(string $json, string $key, int $depth = 512, bool $throw_if_uncountable = false) : int {}
134150

135151
/**
136152
* Returns true if the JSON pointer $key could be found.
137153
*
138-
* @return ?bool (null if depth is invalid, false if json is invalid or key is not found)
139-
* @throws SimdJsonException for invalid JSON
154+
* @param string $json The JSON string being decoded
155+
* @param string $key The JSON pointer being requested
156+
* @param int $depth the maximum nesting depth of the structure being decoded.
157+
* @return bool (false if key is not found)
158+
* @throws SimdJsonException for invalid JSON or invalid JSON pointer
140159
* (or document over 4GB, or out of range integer/float)
160+
* @throws SimdJsonValueError for invalid $depth
161+
* @see https://www.rfc-editor.org/rfc/rfc6901.html
141162
*/
142-
function simdjson_key_exists(string $json, string $key, int $depth = 512) : ?bool {}
163+
function simdjson_key_exists(string $json, string $key, int $depth = 512) : bool {}
143164

144165
/**
145-
* Returns the value at $key
166+
* Returns the value at the json pointer $key
146167
*
168+
* @param string $json The JSON string being decoded
169+
* @param string $key The JSON pointer being requested
170+
* @param int $depth the maximum nesting depth of the structure being decoded.
171+
* @param bool $associative When true, JSON objects will be returned as associative arrays.
172+
* When false, JSON objects will be returned as objects.
147173
* @return array|stdClass|string|float|int|bool|null the value at $key
148-
* @throws SimdJsonException for invalid JSON
174+
* @throws SimdJsonException for invalid JSON or invalid JSON pointer
149175
* (or document over 4GB, or out of range integer/float)
176+
* @throws SimdJsonValueError for invalid $depth
177+
* @see https://www.rfc-editor.org/rfc/rfc6901.html
150178
*/
151-
function simdjson_key_value(string $json, string $key, bool $assoc = unknown, int $depth = unknown) {}
179+
function simdjson_key_value(string $json, string $key, bool $associative = false, int $depth = 512) {}
152180

153181
/**
154182
* An error thrown by simdjson when processing json.
@@ -160,12 +188,27 @@ function simdjson_key_value(string $json, string $key, bool $assoc = unknown, in
160188
*/
161189
class SimdJsonException extends RuntimeException {
162190
}
191+
192+
/**
193+
* Thrown for error conditions on fields such as $depth that are not expected to be
194+
* from user-provided JSON, with similar behavior to php 8.0.
195+
*
196+
* NOTE: https://www.php.net/valueerror was added in php 8.0.
197+
* In older php versions, this extends Error instead.
198+
*
199+
* When support for php 8.0 is dropped completely,
200+
* a major release of simdjson will likely switch to a standard ValueError.
201+
*/
202+
class SimdJsonValueError extends ValueError {
203+
}
163204
```
164205

165206
## Edge cases
166207

167208
There are some differences from `json_decode()` due to the implementation of the underlying simdjson library. This will throw a RuntimeException if simdjson rejects the JSON.
168209

210+
Note that the simdjson PECL is using a fork of the simdjson C library to imitate php's handling of integers and floats in JSON.
211+
169212
1) **Until simdjson 2.1.0,** `simdjson_decode()` differed in how out of range 64-bit integers and floats are handled.
170213

171214
See https://github.com/simdjson/simdjson/blob/master/doc/basics.md#standard-compliance

config.m4

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,11 @@ if test "$PHP_SIMDJSON" != "no"; then
3333
dnl Disable development checks of C simdjson library in php debug builds (can manually override)
3434
PHP_NEW_EXTENSION(simdjson, [
3535
php_simdjson.cpp \
36-
src/bindings.cpp \
36+
src/simdjson_bindings.cpp \
3737
src/simdjson.cpp],
3838
$ext_shared,, "-std=c++17 -DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 -DSIMDJSON_EXCEPTIONS=0 -DSIMDJSON_DEVELOPMENT_CHECKS=0", cxx)
3939

40-
PHP_INSTALL_HEADERS([ext/simdjson], [php_simdjson.h, src/bindings.h src/bindings_defs.h])
40+
PHP_INSTALL_HEADERS([ext/simdjson], [php_simdjson.h src/simdjson_bindings_defs.h])
4141
PHP_ADD_MAKEFILE_FRAGMENT
4242
PHP_ADD_BUILD_DIR(src, 1)
4343
fi

config.w32

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,8 @@ if (PHP_SIMDJSON == "yes") {
99
'php_simdjson.cpp',
1010
'yes',
1111
'/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1 /std:c++latest');
12-
ADD_SOURCES(configure_module_dirname + '/src', 'simdjson.cpp bindings.cpp', 'simdjson');
12+
ADD_SOURCES(configure_module_dirname + '/src', 'simdjson.cpp simdjson_bindings.cpp', 'simdjson');
1313
ADD_FLAG('CFLAGS_SIMDJSON', '/I' + configure_module_dirname);
14-
PHP_INSTALL_HEADERS('ext/simdjson', 'php_simdjson.h src/bindings.h src/bindings_defs.h');
14+
PHP_INSTALL_HEADERS('ext/simdjson', 'php_simdjson.h src/simdjson_bindings_defs.h');
1515
}
1616
// vim:ft=javascript

package.xml

Lines changed: 35 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -20,23 +20,23 @@
2020
-->
2121
<date>2022-10-14</date>
2222
<version>
23-
<release>2.1.0</release>
24-
<api>2.1.0</api>
23+
<release>3.0.0dev</release>
24+
<api>3.0.0dev</api>
2525
</version>
2626
<stability>
2727
<release>stable</release>
2828
<api>stable</api>
2929
</stability>
3030
<license uri="https://www.apache.org/licenses/LICENSE-2.0.html">Apache 2.0</license>
3131
<notes>
32-
* Allow out of range 64-bit values in JSON integer syntax and allow floating point values outside of the max/min finite floating point values (i.e. parsing to +/- infinity).
33-
34-
This allows simdjson_decode() to be used as a replacement for json_decode() in more use cases.
35-
* Return the correct value in simdjson_key_count() for JSON pointers to arrays/objects exceeding size 0xFFFFFF.
36-
Previously, this would be limited to returning at most 0xFFFFFF(16777215).
37-
* Throw 'SimdJsonException extends RuntimeException' instead of RuntimeException.
38-
* Set the error code from simdjson as SimdJsonException->getCode()
39-
* Expose error_code constants from simdjson as `SIMDJSON_ERR_$ERRCODENAME`
32+
* Add SimdJsonValueError. In php 8.0+, it extends ValueError, and it extends Error in older php versions.
33+
This provides an API similar to the JSON module, which started throwing ValueError for invalid depths in php 8.0.
34+
* Throw SimdJsonValueError instead of emitting notices if $depth is too small or too large in all simdjson PHP functions.
35+
simdjson_is_valid(), simdjson_key_count() and simdjson_key_exists() now have non-null return types.
36+
* Throw a SimdJsonException in simdjson_key_exists on error conditions such as invalid json, to be consistent with other simdjson PHP functions.
37+
* Add an optional boolean `$throw_if_uncountable = false` to simdjson_key_count.
38+
When this is overridden to be true, simdjson_key_count will throw a SimdJsonException if the JSON pointer refers to a value that exists but is neither an array nor an object instead of returning 0.
39+
* Rename the parameter $assoc to $associative in simdjson_decode and simdjson_key_value, to match naming practices used in json_decode()
4040
</notes>
4141
<contents>
4242
<dir name="/">
@@ -51,9 +51,8 @@
5151
<file name="simdjson.stub.php" role="src"/>
5252
<file name="simdjson_arginfo.h" role="src"/>
5353
<dir name="src">
54-
<file name="bindings.cpp" role="src"/>
55-
<file name="bindings.h" role="src"/>
56-
<file name="bindings_defs.h" role="src"/>
54+
<file name="simdjson_bindings.cpp" role="src"/>
55+
<file name="simdjson_bindings_defs.h" role="src"/>
5756
<file name="simdjson.cpp" role="src"/>
5857
<file name="simdjson.h" role="src"/>
5958
</dir>
@@ -71,6 +70,7 @@
7170
<file name="decode_strict_types.phpt" role="test"/>
7271
<file name="decode_types.phpt" role="test"/>
7372
<file name="depth.phpt" role="test"/>
73+
<file name="dump.inc" role="test"/>
7474
<file name="is_valid.phpt" role="test"/>
7575
<file name="is_valid_args.phpt" role="test"/>
7676
<file name="key_count.phpt" role="test"/>
@@ -101,7 +101,6 @@
101101
<file name="bug69187.phpt" role="test"/>
102102
<file name="fail001.phpt" role="test"/>
103103
<file name="json_decode_basic.phpt" role="test"/>
104-
<file name="json_decode_error.phpt" role="test"/>
105104
<file name="json_decode_invalid_utf8.phpt" role="test"/>
106105
<file name="pass001.1_64bit.phpt" role="test"/>
107106
<file name="pass001.1.phpt" role="test"/>
@@ -125,6 +124,28 @@
125124
<providesextension>simdjson</providesextension>
126125
<extsrcrelease/>
127126
<changelog>
127+
<release>
128+
<date>2022-10-14</date>
129+
<version>
130+
<release>2.1.0</release>
131+
<api>2.1.0</api>
132+
</version>
133+
<stability>
134+
<release>stable</release>
135+
<api>stable</api>
136+
</stability>
137+
<license uri="https://www.apache.org/licenses/LICENSE-2.0.html">Apache 2.0</license>
138+
<notes>
139+
* Allow out of range 64-bit values in JSON integer syntax and allow floating point values outside of the max/min finite floating point values (i.e. parsing to +/- infinity).
140+
141+
This allows simdjson_decode() to be used as a replacement for json_decode() in more use cases.
142+
* Return the correct value in simdjson_key_count() for JSON pointers to arrays/objects exceeding size 0xFFFFFF.
143+
Previously, this would be limited to returning at most 0xFFFFFF(16777215).
144+
* Throw 'SimdJsonException extends RuntimeException' instead of RuntimeException.
145+
* Set the error code from simdjson as SimdJsonException->getCode()
146+
* Expose error_code constants from simdjson as `SIMDJSON_ERR_$ERRCODENAME`
147+
</notes>
148+
</release>
128149
<release>
129150
<date>2022-10-01</date>
130151
<version>

0 commit comments

Comments
 (0)