summaryrefslogtreecommitdiff
path: root/ext/json/json_encoder.c
diff options
context:
space:
mode:
Diffstat (limited to 'ext/json/json_encoder.c')
-rw-r--r--ext/json/json_encoder.c103
1 files changed, 81 insertions, 22 deletions
diff --git a/ext/json/json_encoder.c b/ext/json/json_encoder.c
index 92e4a10933..c76ddaf0fd 100644
--- a/ext/json/json_encoder.c
+++ b/ext/json/json_encoder.c
@@ -27,6 +27,7 @@
#include "php_json.h"
#include "php_json_encoder.h"
#include <zend_exceptions.h>
+#include "zend_enum.h"
static const char digits[] = "0123456789abcdef";
@@ -36,29 +37,10 @@ static int php_json_escape_string(
static int php_json_determine_array_type(zval *val) /* {{{ */
{
- int i;
- HashTable *myht = Z_ARRVAL_P(val);
-
- i = myht ? zend_hash_num_elements(myht) : 0;
- if (i > 0) {
- zend_string *key;
- zend_ulong index, idx;
+ zend_array *myht = Z_ARRVAL_P(val);
- if (HT_IS_PACKED(myht) && HT_IS_WITHOUT_HOLES(myht)) {
- return PHP_JSON_OUTPUT_ARRAY;
- }
-
- idx = 0;
- ZEND_HASH_FOREACH_KEY(myht, index, key) {
- if (key) {
- return PHP_JSON_OUTPUT_OBJECT;
- } else {
- if (index != idx) {
- return PHP_JSON_OUTPUT_OBJECT;
- }
- }
- idx++;
- } ZEND_HASH_FOREACH_END();
+ if (myht) {
+ return zend_array_is_list(myht) ? PHP_JSON_OUTPUT_ARRAY : PHP_JSON_OUTPUT_OBJECT;
}
return PHP_JSON_OUTPUT_ARRAY;
@@ -134,6 +116,67 @@ static int php_json_encode_array(smart_str *buf, zval *val, int options, php_jso
myht = Z_ARRVAL_P(val);
prop_ht = NULL;
r = (options & PHP_JSON_FORCE_OBJECT) ? PHP_JSON_OUTPUT_OBJECT : php_json_determine_array_type(val);
+ } else if (Z_OBJ_P(val)->properties == NULL
+ && Z_OBJ_HT_P(val)->get_properties_for == NULL
+ && Z_OBJ_HT_P(val)->get_properties == zend_std_get_properties) {
+ /* Optimized version without rebulding properties HashTable */
+ zend_object *obj = Z_OBJ_P(val);
+ zend_class_entry *ce = obj->ce;
+ zend_property_info *prop_info;
+ zval *prop;
+ int i;
+
+ if (GC_IS_RECURSIVE(obj)) {
+ encoder->error_code = PHP_JSON_ERROR_RECURSION;
+ smart_str_appendl(buf, "null", 4);
+ return FAILURE;
+ }
+
+ PHP_JSON_HASH_PROTECT_RECURSION(obj);
+ smart_str_appendc(buf, '{');
+ for (i = 0; i < ce->default_properties_count; i++) {
+ prop_info = ce->properties_info_table[i];
+ if (!prop_info) {
+ continue;
+ }
+ if (ZSTR_VAL(prop_info->name)[0] == '\0' && ZSTR_LEN(prop_info->name) > 0) {
+ /* Skip protected and private members. */
+ continue;
+ }
+ prop = OBJ_PROP(obj, prop_info->offset);
+ if (Z_TYPE_P(prop) == IS_UNDEF) {
+ continue;
+ }
+
+ if (need_comma) {
+ smart_str_appendc(buf, ',');
+ } else {
+ need_comma = 1;
+ }
+
+ php_json_pretty_print_char(buf, options, '\n');
+ php_json_pretty_print_indent(buf, options, encoder);
+
+ if (php_json_escape_string(buf, ZSTR_VAL(prop_info->name), ZSTR_LEN(prop_info->name),
+ options & ~PHP_JSON_NUMERIC_CHECK, encoder) == FAILURE &&
+ (options & PHP_JSON_PARTIAL_OUTPUT_ON_ERROR) &&
+ buf->s) {
+ ZSTR_LEN(buf->s) -= 4;
+ smart_str_appendl(buf, "\"\"", 2);
+ }
+
+ smart_str_appendc(buf, ':');
+ php_json_pretty_print_char(buf, options, ' ');
+
+ if (php_json_encode_zval(buf, prop, options, encoder) == FAILURE &&
+ !(options & PHP_JSON_PARTIAL_OUTPUT_ON_ERROR)) {
+ PHP_JSON_HASH_UNPROTECT_RECURSION(obj);
+ return FAILURE;
+ }
+ }
+ smart_str_appendc(buf, '}');
+ PHP_JSON_HASH_UNPROTECT_RECURSION(obj);
+ return SUCCESS;
} else {
prop_ht = myht = zend_get_properties_for(val, ZEND_PROP_PURPOSE_JSON);
r = PHP_JSON_OUTPUT_OBJECT;
@@ -528,6 +571,19 @@ static int php_json_encode_serializable_object(smart_str *buf, zval *val, int op
}
/* }}} */
+static int php_json_encode_serializable_enum(smart_str *buf, zval *val, int options, php_json_encoder *encoder)
+{
+ zend_class_entry *ce = Z_OBJCE_P(val);
+ if (ce->enum_backing_type == IS_UNDEF) {
+ encoder->error_code = PHP_JSON_ERROR_NON_BACKED_ENUM;
+ smart_str_appendc(buf, '0');
+ return FAILURE;
+ }
+
+ zval *value_zv = zend_enum_fetch_case_value(Z_OBJ_P(val));
+ return php_json_encode_zval(buf, value_zv, options, encoder);
+}
+
int php_json_encode_zval(smart_str *buf, zval *val, int options, php_json_encoder *encoder) /* {{{ */
{
again:
@@ -564,6 +620,9 @@ again:
if (instanceof_function(Z_OBJCE_P(val), php_json_serializable_ce)) {
return php_json_encode_serializable_object(buf, val, options, encoder);
}
+ if (Z_OBJCE_P(val)->ce_flags & ZEND_ACC_ENUM) {
+ return php_json_encode_serializable_enum(buf, val, options, encoder);
+ }
/* fallthrough -- Non-serializable object */
case IS_ARRAY: {
/* Avoid modifications (and potential freeing) of the array through a reference when a