Skip to content

Commit

Permalink
Switch from RuntimeException to SimdJsonException
Browse files Browse the repository at this point in the history
1. Change to SimdJsonException extends RuntimeException.
   The name was chosen to be similar to https://www.php.net/jsonexception
   JsonException.
2. Set the value of $e->getCode()
3. Add global constants `SIMDJSON_ERR_*`
  • Loading branch information
TysonAndre committed Oct 2, 2022
1 parent bf7357c commit e044b8b
Show file tree
Hide file tree
Showing 15 changed files with 167 additions and 129 deletions.
10 changes: 5 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,36 +109,36 @@ var_dump($res) //int(5)
/**
* Similar to json_decode()
*
* @returns array|stdClass|string|float|int|bool|null
* @return array|stdClass|string|float|int|bool|null
* @throws RuntimeException for invalid JSON (or document over 4GB, or out of range integer/float)
*/
function simdjson_decode(string $json, bool $assoc = false, int $depth = 512) {}

/**
* Returns true if json is valid.
*
* @returns ?bool (null if depth is invalid)
* @return ?bool (null if depth is invalid)
*/
function simdjson_is_valid(string $json, int $depth = 512) : ?bool {}

/**
* Parses $json and returns the number of keys in $json matching the JSON pointer $key
*
* @returns ?bool (null if depth is invalid)
* @return ?int (null if depth is invalid)
*/
function simdjson_key_count(string $json, string $key, int $depth = 512) : ?int {}

/**
* Returns true if the JSON pointer $key could be found.
*
* @returns ?bool (null if depth is invalid, false if json is invalid or key is not found)
* @return ?bool (null if depth is invalid, false if json is invalid or key is not found)
*/
function simdjson_key_exists(string $json, string $key, int $depth = 512) : ?bool {}

/**
* Returns the value at $key
*
* @returns array|stdClass|string|float|int|bool|null the value at $key
* @return array|stdClass|string|float|int|bool|null the value at $key
* @throws RuntimeException for invalid JSON (or document over 4GB, or out of range integer/float)
*/
function simdjson_key_value(string $json, string $key, bool $assoc = unknown, int $depth = unknown) {}
Expand Down
5 changes: 5 additions & 0 deletions package.xml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@
This allows simdjson_decode() to be used as a replacement for json_decode() in more use cases.
* Return the correct value in simdjson_key_count() for JSON pointers to arrays/objects exceeding size 0xFFFFFF.
Previously, this would be limited to returning at most 0xFFFFFF(16777215).
* Throw 'SimdJsonException extends RuntimeException' instead of RuntimeException.
* Set the error code from simdjson as SimdJsonException->getCode()
* Expose error_code constants from simdjson as `SIMDJSON_ERR_$ERRCODENAME`
</notes>
<contents>
<dir name="/">
Expand All @@ -45,6 +48,8 @@
<file name="php_simdjson.h" role="src"/>
<file name="php_simdjson.cpp" role="src"/>
<file name="README.md" role="doc"/>
<file name="simdjson.stub.php" role="src"/>
<file name="simdjson_arginfo.h" role="src"/>
<dir name="src">
<file name="bindings.cpp" role="src"/>
<file name="bindings.h" role="src"/>
Expand Down
37 changes: 37 additions & 0 deletions php_simdjson.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,18 @@ extern "C" {
#include "zend_exceptions.h"
#include "main/SAPI.h"
#include "ext/standard/info.h"
#include "ext/spl/spl_exceptions.h"

#include "php_simdjson.h"
#include "simdjson_arginfo.h"
}

#include "src/bindings.h"

ZEND_DECLARE_MODULE_GLOBALS(simdjson);

ZEND_API zend_class_entry *simdjson_exception_ce;

#if PHP_VERSION_ID >= 70200
#define SIMDJSON_ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(name, return_reference, required_num_args, type, allow_null) \
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(name, return_reference, required_num_args, type, allow_null)
Expand Down Expand Up @@ -202,7 +206,40 @@ ZEND_TSRMLS_CACHE_UPDATE();

/** {{{ PHP_MINIT_FUNCTION
*/
#define SIMDJSON_REGISTER_ERROR_CODE_CONSTANT(errcode) REGISTER_LONG_CONSTANT("SIMDJSON_ERR_" #errcode, simdjson::errcode, CONST_PERSISTENT)
PHP_MINIT_FUNCTION (simdjson) {
simdjson_exception_ce = register_class_SimdJsonException(spl_ce_RuntimeException);
SIMDJSON_REGISTER_ERROR_CODE_CONSTANT(CAPACITY); ///< This parser can't support a document that big
// SIMDJSON_REGISTER_ERROR_CODE_CONSTANT(MEMALLOC); ///< Error allocating memory, most likely out of memory
SIMDJSON_REGISTER_ERROR_CODE_CONSTANT(TAPE_ERROR); ///< Something went wrong, this is a generic error
SIMDJSON_REGISTER_ERROR_CODE_CONSTANT(DEPTH_ERROR); ///< Your document exceeds the user-specified depth limitation
SIMDJSON_REGISTER_ERROR_CODE_CONSTANT(STRING_ERROR); ///< Problem while parsing a string
SIMDJSON_REGISTER_ERROR_CODE_CONSTANT(T_ATOM_ERROR); ///< Problem while parsing an atom starting with the letter 't'
SIMDJSON_REGISTER_ERROR_CODE_CONSTANT(F_ATOM_ERROR); ///< Problem while parsing an atom starting with the letter 'f'
SIMDJSON_REGISTER_ERROR_CODE_CONSTANT(N_ATOM_ERROR); ///< Problem while parsing an atom starting with the letter 'n'
SIMDJSON_REGISTER_ERROR_CODE_CONSTANT(NUMBER_ERROR); ///< Problem while parsing a number
SIMDJSON_REGISTER_ERROR_CODE_CONSTANT(UTF8_ERROR); ///< the input is not valid UTF-8
SIMDJSON_REGISTER_ERROR_CODE_CONSTANT(UNINITIALIZED); ///< unknown error, or uninitialized document
SIMDJSON_REGISTER_ERROR_CODE_CONSTANT(EMPTY); ///< no structural element found
SIMDJSON_REGISTER_ERROR_CODE_CONSTANT(UNESCAPED_CHARS); ///< found unescaped characters in a string.
SIMDJSON_REGISTER_ERROR_CODE_CONSTANT(UNCLOSED_STRING); ///< missing quote at the end
SIMDJSON_REGISTER_ERROR_CODE_CONSTANT(UNSUPPORTED_ARCHITECTURE); ///< unsupported architecture
SIMDJSON_REGISTER_ERROR_CODE_CONSTANT(INCORRECT_TYPE); ///< JSON element has a different type than user expected
SIMDJSON_REGISTER_ERROR_CODE_CONSTANT(NUMBER_OUT_OF_RANGE); ///< JSON number does not fit in 64 bits
SIMDJSON_REGISTER_ERROR_CODE_CONSTANT(INDEX_OUT_OF_BOUNDS); ///< JSON array index too large
SIMDJSON_REGISTER_ERROR_CODE_CONSTANT(NO_SUCH_FIELD); ///< JSON field not found in object
SIMDJSON_REGISTER_ERROR_CODE_CONSTANT(IO_ERROR); ///< Error reading a file
SIMDJSON_REGISTER_ERROR_CODE_CONSTANT(INVALID_JSON_POINTER); ///< Invalid JSON pointer reference
SIMDJSON_REGISTER_ERROR_CODE_CONSTANT(INVALID_URI_FRAGMENT); ///< Invalid URI fragment
SIMDJSON_REGISTER_ERROR_CODE_CONSTANT(UNEXPECTED_ERROR); ///< indicative of a bug in simdjson
SIMDJSON_REGISTER_ERROR_CODE_CONSTANT(PARSER_IN_USE); ///< parser is already in use.
SIMDJSON_REGISTER_ERROR_CODE_CONSTANT(OUT_OF_ORDER_ITERATION); ///< tried to iterate an array or object out of order
SIMDJSON_REGISTER_ERROR_CODE_CONSTANT(INSUFFICIENT_PADDING); ///< The JSON doesn't have enough padding for simdjson to safely parse it.
SIMDJSON_REGISTER_ERROR_CODE_CONSTANT(INCOMPLETE_ARRAY_OR_OBJECT); ///< The document ends early.
SIMDJSON_REGISTER_ERROR_CODE_CONSTANT(SCALAR_DOCUMENT_AS_VALUE); ///< A scalar document is treated as a value.
SIMDJSON_REGISTER_ERROR_CODE_CONSTANT(OUT_OF_BOUNDS); ///< Attempted to access location outside of document.
SIMDJSON_REGISTER_ERROR_CODE_CONSTANT(TRAILING_CONTENT); ///< Unexpected trailing content in the JSON input

return SUCCESS;
}
/* }}} */
Expand Down
11 changes: 11 additions & 0 deletions simdjson.stub.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php
/**
* This is used with php-src's build/gen_stubs.php to generate argument info compatible with php 7.0 and above.
*
* See README.md for function documentation.
*
* @generate-class-entries
*/

class SimdJsonException extends RuntimeException {
}
19 changes: 19 additions & 0 deletions simdjson_arginfo.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/* This is a generated file, edit the .stub.php file instead.
* Stub hash: e7f05ec4984c79ce2696174896f000a7082de6ed */




static const zend_function_entry class_SimdJsonException_methods[] = {
ZEND_FE_END
};

static zend_class_entry *register_class_SimdJsonException(zend_class_entry *class_entry_RuntimeException)
{
zend_class_entry ce, *class_entry;

INIT_CLASS_ENTRY(ce, "SimdJsonException", class_SimdJsonException_methods);
class_entry = zend_register_internal_class_ex(&ce, class_entry_RuntimeException);

return class_entry;
}
15 changes: 10 additions & 5 deletions src/bindings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ extern "C" {

#define SIMDJSON_DEPTH_CHECK_THRESHOLD 100000

static void simdjson_throw_jsonexception(simdjson::error_code error)
{
zend_throw_exception(simdjson_exception_ce, simdjson::error_message(error), (zend_long) error);
}

static inline simdjson::simdjson_result<simdjson::dom::element>
get_key_with_optional_prefix(simdjson::dom::element &doc, std::string_view json_pointer)
{
Expand Down Expand Up @@ -317,7 +322,7 @@ void cplus_simdjson_parse(simdjson::dom::parser& parser, const char *json, size_
simdjson::dom::element doc;
auto error = build_parsed_json_cust(parser, doc, json, len, true, depth);
if (error) {
zend_throw_exception(spl_ce_RuntimeException, simdjson::error_message(error), 0);
simdjson_throw_jsonexception(error);
return;
}

Expand All @@ -334,14 +339,14 @@ void cplus_simdjson_key_value(simdjson::dom::parser& parser, const char *json, s
simdjson::dom::element element;
auto error = build_parsed_json_cust(parser, doc, json, len, true, depth);
if (error) {
zend_throw_exception(spl_ce_RuntimeException, simdjson::error_message(error), 0);
simdjson_throw_jsonexception(error);
return;
}

error = get_key_with_optional_prefix(doc, key).get(element);

if (error) {
zend_throw_exception(spl_ce_RuntimeException, simdjson::error_message(error), 0);
simdjson_throw_jsonexception(error);
return;
}

Expand Down Expand Up @@ -376,13 +381,13 @@ void cplus_simdjson_key_count(simdjson::dom::parser& parser, const char *json, s

auto error = build_parsed_json_cust(parser, doc, json, len, true, depth);
if (error) {
zend_throw_exception(spl_ce_RuntimeException, simdjson::error_message(error), 0);
simdjson_throw_jsonexception(error);
return;
}

error = get_key_with_optional_prefix(doc, key).get(element);
if (error) {
zend_throw_exception(spl_ce_RuntimeException, simdjson::error_message(error), 0);
simdjson_throw_jsonexception(error);
return;
}

Expand Down
2 changes: 2 additions & 0 deletions src/bindings.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@

#include "simdjson.h"

extern zend_class_entry *simdjson_exception_ce;

simdjson::dom::parser* cplus_simdjson_create_parser(void);
void cplus_simdjson_free_parser(simdjson::dom::parser* parser);
bool cplus_simdjson_is_valid(const char *json, size_t len);
Expand Down
41 changes: 0 additions & 41 deletions tests/compat/bug41403.phpt

This file was deleted.

2 changes: 1 addition & 1 deletion tests/compat/bug62010.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@ try {
}
?>
--EXPECT--
Caught RuntimeException: Problem while parsing a string
Caught SimdJsonException: Problem while parsing a string
14 changes: 7 additions & 7 deletions tests/compat/bug64874_part2.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ Case-sensitivity part of bug #64874 compat ("json_decode handles whitespace and
function decode($json) {
try {
var_dump(simdjson_decode($json));
} catch (RuntimeException $e) {
} catch (SimdJsonException $e) {
printf("Caught %s: %s\n", get_class($e), $e->getMessage());
}
}
Expand Down Expand Up @@ -33,27 +33,27 @@ echo "Done\n";
?>
--EXPECT--
bool(true)
Caught RuntimeException: The JSON document has an improper structure: missing or superfluous commas, braces, missing keys, etc.
Caught SimdJsonException: The JSON document has an improper structure: missing or superfluous commas, braces, missing keys, etc.
array(1) {
[0]=>
bool(true)
}
Caught RuntimeException: The JSON document has an improper structure: missing or superfluous commas, braces, missing keys, etc.
Caught SimdJsonException: The JSON document has an improper structure: missing or superfluous commas, braces, missing keys, etc.

bool(false)
Caught RuntimeException: The JSON document has an improper structure: missing or superfluous commas, braces, missing keys, etc.
Caught SimdJsonException: The JSON document has an improper structure: missing or superfluous commas, braces, missing keys, etc.
array(1) {
[0]=>
bool(false)
}
Caught RuntimeException: The JSON document has an improper structure: missing or superfluous commas, braces, missing keys, etc.
Caught SimdJsonException: The JSON document has an improper structure: missing or superfluous commas, braces, missing keys, etc.

NULL
Caught RuntimeException: The JSON document has an improper structure: missing or superfluous commas, braces, missing keys, etc.
Caught SimdJsonException: The JSON document has an improper structure: missing or superfluous commas, braces, missing keys, etc.
array(1) {
[0]=>
NULL
}
Caught RuntimeException: The JSON document has an improper structure: missing or superfluous commas, braces, missing keys, etc.
Caught SimdJsonException: The JSON document has an improper structure: missing or superfluous commas, braces, missing keys, etc.

Done
4 changes: 2 additions & 2 deletions tests/compat/bug68938.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ Bug #68938 compat (json_decode() decodes empty string without indicating error)
<?php
try {
simdjson_decode("");
} catch (RuntimeException $e) {
} catch (SimdJsonException $e) {
printf("Caught %s: %s\n", get_class($e), $e->getMessage());
}
?>
--EXPECT--
Caught RuntimeException: Empty: no JSON found
Caught SimdJsonException: Empty: no JSON found
28 changes: 14 additions & 14 deletions tests/compat/bug69187.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ function compat_decode($value) {
$lasterr = 0;
try {
return simdjson_decode($value);
} catch (RuntimeException $e) {
return sprintf("%s: %s", get_class($e), $e->getMessage());
} catch (SimdJsonException $e) {
return sprintf("%s: %d: %s", get_class($e), $e->getCode(), $e->getMessage());
}
}
var_dump(compat_decode(FALSE));
Expand All @@ -18,23 +18,23 @@ var_dump(compat_decode(0));
var_dump(compat_decode(1));
var_dump(compat_decode(TRUE));

compat_decode("\xED\xA0\xB4");
var_dump(compat_decode("\xED\xA0\xB4"));

compat_decode("\x00");
var_dump($lasterr);
var_dump(compat_decode("\x00"));

compat_decode("\"\xED\xA0\xB4\"");
var_dump($lasterr);
var_dump(compat_decode("\"\xED\xA0\xB4\""));

compat_decode("\"\x00\"");
var_dump($lasterr);
var_dump(compat_decode("\"\x00\""));
var_dump(SIMDJSON_ERR_UNESCAPED_CHARS);
?>
--EXPECT--
string(38) "RuntimeException: Empty: no JSON found"
string(38) "RuntimeException: Empty: no JSON found"
string(43) "SimdJsonException: 12: Empty: no JSON found"
string(43) "SimdJsonException: 12: Empty: no JSON found"
int(0)
int(1)
int(1)
int(0)
int(0)
int(0)
string(51) "SimdJsonException: 10: The input is not valid UTF-8"
string(124) "SimdJsonException: 3: The JSON document has an improper structure: missing or superfluous commas, braces, missing keys, etc."
string(51) "SimdJsonException: 10: The input is not valid UTF-8"
string(101) "SimdJsonException: 13: Within strings, some characters must be escaped, we found unescaped characters"
int(13)
Loading

0 comments on commit e044b8b

Please sign in to comment.