源码分析系列之json_encode()如何转化一个对象

  static int php_json_encode_array(smart_str *buf, zval *val, int options, php_json_encoder *encoder) /* {{{ */

  {

  int i, r, need_comma = 0;

  HashTable *myht;

  // r用来表示输出 `json` 的结构类型是数组还是对象

  // 只有自然排序的数组(['a','b','c'])才有可能被输出为数组(考虑option可能为JSON_FORCE_OBJECT)

  if (Z_TYPE_P(val) == IS_ARRAY) {

  // 如果是数组

  myht = Z_ARRVAL_P(val);

  // options中有JSON_FORCE_OBJECT 就强制输出对象,否则就判断数组是不是自然数组

  r = (options & PHP_JSON_FORCE_OBJECT) ? PHP_JSON_OUTPUT_OBJECT : php_json_determine_array_type(val);

  } else {

  myht = Z_OBJPROP_P(val);

  //对象就是输出对象

  r = PHP_JSON_OUTPUT_OBJECT;

  }

  if (myht && ZEND_HASH_GET_APPLY_COUNT(myht) > 0) {

  encoder->error_code = PHP_JSON_ERROR_RECURSION;

  smart_str_appendl(buf, "null", 4);

  return FAILURE;

  }

  PHP_JSON_HASH_APPLY_PROTECTION_INC(myht);

  if (r == PHP_JSON_OUTPUT_ARRAY) {

  //输出为数组 就用 [ 做开头

  smart_str_appendc(buf, '[');

  } else {

  //输出为对象 就用 { 做开头

  smart_str_appendc(buf, '{');

  }

  // 当前递归的深度

  ++encoder->depth;

  // zend_hash_num_elements 返回哈希表中元素的数量

  i = myht ? zend_hash_num_elements(myht) : 0;

  if (i > 0) {

  zend_string *key;

  zval *data;

  zend_ulong index;

  //遍历当前维度的数组 如果当前元素不是数组

  ZEND_HASH_FOREACH_KEY_VAL_IND(myht, index, key, data) {

  // ↓ begin 从这里开始都是判断key怎么处理以及元素末尾怎么处理 ↓↓↓↓

  if (r == PHP_JSON_OUTPUT_ARRAY) {

  //need_comma初始值是0

  if (need_comma) {

  smart_str_appendc(buf, ',');

  } else {

  need_comma = 1;

  }

  //这两个方法是option中有JSON_PRETTY_PRINT的时候才会执行的

  php_json_pretty_print_char(buf, options, '

  ');

  php_json_pretty_print_indent(buf, options, encoder);

  } else if (r == PHP_JSON_OUTPUT_OBJECT) {

  if (key) {

  if (ZSTR_VAL(key)[0] == '0' && ZSTR_LEN(key) > 0 && Z_TYPE_P(val) == IS_OBJECT) {

  //跳过受保护的属性和私有属性

  /* Skip protected and private members. */

  continue;

  }

  //need_comma初始值是0

  if (need_comma) {

  smart_str_appendc(buf, ',');

  } else {

  need_comma = 1;

  }

  php_json_pretty_print_char(buf, options, '

  ');

  php_json_pretty_print_indent(buf, options, encoder);

  // 处理字符串属性的key(例如判断key中的中文或者特殊字符的处理)

  if (php_json_escape_string(buf, ZSTR_VAL(key), ZSTR_LEN(key),

  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);

  }

  } else {

  if (need_comma) {

  smart_str_appendc(buf, ',');

  } else {

  need_comma = 1;

  }

  php_json_pretty_print_char(buf, options, '

  ');

  php_json_pretty_print_indent(buf, options, encoder);

  smart_str_appendc(buf, '"');

  smart_str_append_long(buf, (zend_long) index);

  smart_str_appendc(buf, '"');

  }

  smart_str_appendc(buf, ':');

  php_json_pretty_print_char(buf, options, ' ');

  }

  // ↑ end 从这里之前都是判断key怎么处理以及元素末尾怎么处理 ↑↑↑↑

  //继续调用对普通元素编码的 php_json_encode_zval() (实现数组和对象的递归闭环)

  if (php_json_encode_zval(buf, data, options, encoder) == FAILURE &&

  !(options & PHP_JSON_PARTIAL_OUTPUT_ON_ERROR)) {

  PHP_JSON_HASH_APPLY_PROTECTION_DEC(myht);

  return FAILURE;

  }

  } ZEND_HASH_FOREACH_END();

  }

  PHP_JSON_HASH_APPLY_PROTECTION_DEC(myht);

  // 当前深度是否到达了设定的最大深度(默认512)

  if (encoder->depth > encoder->max_depth) {

  encoder->error_code = PHP_JSON_ERROR_DEPTH;

  if (!(options & PHP_JSON_PARTIAL_OUTPUT_ON_ERROR)) {

  return FAILURE;

  }

  }

  --encoder->depth;

  /* Only keep closing bracket on same line for empty arrays/objects */

  if (need_comma) {

  php_json_pretty_print_char(buf, options, '

  ');

  php_json_pretty_print_indent(buf, options, encoder);

  }

  if (r == PHP_JSON_OUTPUT_ARRAY) {

  smart_str_appendc(buf, ']');

  } else {

  smart_str_appendc(buf, '}');

  }

  return SUCCESS;

  }

  /* }}} */