最新文章专题视频专题问答1问答10问答100问答1000问答2000关键字专题1关键字专题50关键字专题500关键字专题1500TAG最新视频文章推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37视频文章20视频文章30视频文章40视频文章50视频文章60 视频文章70视频文章80视频文章90视频文章100视频文章120视频文章140 视频2关键字专题关键字专题tag2tag3文章专题文章专题2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章专题3
当前位置: 首页 - 正文

PHP的json_encode分析

来源:动视网 责编:小OO 时间:2025-09-28 13:05:20
文档

PHP的json_encode分析

PHP的json_encode分析json的优点就不说了,有个习惯,我在输出json的时候,喜欢用sprintf拼成json格式,前两天被朋友说不标准,必须要用json_encode生成的才是标准的json格式,我当然很郁闷啦,用了这么多年了,刚知道这样做不标准,既然说我不标准,那上面才是标准的json格式? 1.{a : 'abc'} 2.{'a' : 'abc'} 3.{a : "abc"} 4.{"a" : "abc"} 那都知道,只有第四种才是标准的json格式。我这么做 1.$ret
推荐度:
导读PHP的json_encode分析json的优点就不说了,有个习惯,我在输出json的时候,喜欢用sprintf拼成json格式,前两天被朋友说不标准,必须要用json_encode生成的才是标准的json格式,我当然很郁闷啦,用了这么多年了,刚知道这样做不标准,既然说我不标准,那上面才是标准的json格式? 1.{a : 'abc'} 2.{'a' : 'abc'} 3.{a : "abc"} 4.{"a" : "abc"} 那都知道,只有第四种才是标准的json格式。我这么做 1.$ret
PHP的json_encode分析

json的优点就不说了,

有个习惯,我在输出json的时候,喜欢用 sprintf 拼成json格式,

前两天被朋友说不标准,必须要用json_encode生成的才是标准的json格式,我当然很郁闷啦,

用了这么多年了,刚知道 这样做不标准,既然说我不标准,那上面才是标准的json格式?

 

1.{a : 'abc'} 

2.{'a' : 'abc'} 

3.{a : "abc"} 

4.{"a" : "abc"} 

那都知道,只有第四种才是标准的json格式。

我这么做

 

1.$ret_json='{"%s":"%s"}'; 

2.echo json_encode($ret_json,"a

必然也符合标准。

既然如此,那我就要刨根问底,json_encode生成的json格式究竟有什么不同?

上代码

 

1.static PHP_FUNCTION(json_encode) 

2.{ 

3.        zval *parameter; 

4.        smart_str buf = {0}; 

5.        long options = 0; 

6.  

7.        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|l", ¶meter, &options) == FAILURE) { 

8.                return; 

9.        }    

10.  

11.        JSON_G(error_code) = PHP_JSON_ERROR_NONE; 

12.  

13.        php_json_encode(&buf, parameter, options TSRMLS_CC); 

14.  

15.        ZVAL_STRINGL(return_value, buf.c, buf.len, 1);  

16.  

17.        smart_str_free(&buf); 

18.} 

JSON_G(error_code) = PHP_JSON_ERROR_NONE;

是定义的json错误,该错误可以通过json_last_error函数获取,你用过吗?反正我没用过。

php_json_encode是主要的操作

 

1.PHP_JSON_API void php_json_encode(smart_str *buf, zval *val, int options TSRMLS_DC) /* {{{ */ 

2.{ 

3.        switch (Z_TYPE_P(val)) 

4.        { 

5.                case IS_NULL: 

6.                        smart_str_appendl(buf, "null", 4); //输出NULL 

7.                        break; 

8.  

9.                case IS_BOOL: 

10.                        if (Z_BVAL_P(val)) { 

11.                                smart_str_appendl(buf, "true", 4);//输出true 

12.                        } else { 

13.                                smart_str_appendl(buf, "false", 5);//输出false 

14.                        } 

15.                        break; 

16.  

17.                case IS_LONG: 

18.                        smart_str_append_long(buf, Z_LVAL_P(val));//输出长整形的值 

19.                        break; 

20.  

21.                case IS_DOUBLE: 

22.                        { 

23.                                char *d = NULL; 

24.                                int len; 

25.                                double dbl = Z_DVAL_P(val); 

26.  

27.                                if (!zend_isinf(dbl) && !zend_isnan(dbl)) {//非无穷尽 

28.                                        len = spprintf(&d, 0, "%.*k", (int) EG(precision), dbl); 

29.                                        smart_str_appendl(buf, d, len); 

30.                                        efree(d); 

31.                                } else { 

32.                                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "double %.9g does not conform to the JSON spec, encoded as 0", dbl); 

33.                                        smart_str_appendc(buf, '0'); 

34.                                } 

35.                       } 

36.                        break; 

37.  

38.                case IS_STRING://字符串 

39.                        json_escape_string(buf, Z_STRVAL_P(val), Z_STRLEN_P(val), options TSRMLS_CC); 

40.                        break; 

41.  

42.                case IS_ARRAY://数组和对象 

43.                case IS_OBJECT: 

44.                        json_encode_array(buf, &val, options TSRMLS_CC); 

45.                        break; 

46.  

47.                default: 

48.                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "type is unsupported, encoded as null"); 

49.                        smart_str_appendl(buf, "null", 4); 

50.                        break; 

51.        } 

52.  

53.        return; 

54.} 

很明显,根据不同的类型,会有相应的case。

最复杂的是 字符串 、数组 、对象这三种类型,数组和对象是同一种操作。

先看看字符串吧,很长,注释直接写在代码里。

 

1.//options应该是5.3版本之后才支持的,由以下常量组成的二进制掩码: JSON_HEX_QUOT, JSON_HEX_TAG, JSON_HEX_AMP, JSON_HEX_APOS, JSON_NUMERIC_CHECK, JSON_PRETTY_PRINT, JSON_UNESCAPED_SLASHES, JSON_FORCE_OBJECT, JSON_UNESCAPED_UNICODE.虽然我没用过。。 

2.static void json_escape_string(smart_str *buf, char *s, int len, int options TSRMLS_DC) /* {{{ */ 

3.{ 

4.        int pos = 0; 

5.        unsigned short us; 

6.        unsigned short *utf16; 

7.  

8.        if (len == 0) {//如果长度为0,则直接返回 双引号 "" 

9.                smart_str_appendl(buf, "\\"\\"", 2); 

10.                return; 

11.        } 

12.  

13.        if (options & PHP_JSON_NUMERIC_CHECK) {//检测是否为0-9的数字,如果是数字,那么就会直接把数据作为long或double类型返回。 

14.                double d; 

15.                int type; 

16.                long p; 

17.  

18.                if ((type = is_numeric_string(s, len, &p, &d, 0)) != 0) { 

19.                        if (type == IS_LONG) { 

20.                                smart_str_append_long(buf, p); 

21.                        } else if (type == IS_DOUBLE) { 

22.                                if (!zend_isinf(d) && !zend_isnan(d)) { 

23.                                        char *tmp; 

24.                                        int l = spprintf(&tmp, 0, "%.*k", (int) EG(precision), d); 

25.                                        smart_str_appendl(buf, tmp, l); 

26.                                        efree(tmp); 

27.                                } else { 

28.                                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "double %.9g does not conform to the JSON spec, encoded as 0", d); 

29.                                        smart_str_appendc(buf, '0'); 

30.                                } 

31.                        } 

32.                        return; 

33.                } 

34.  

35.        } 

36.  

37.        utf16 = (unsigned short *) safe_emalloc(len, sizeof(unsigned short), 0); 

38.        len = utf8_to_utf16(utf16, s, len); //这里会对你输入的值一次处理转成对应的Dec码,比如1是49,a是97这样的,保存到utf16中。 

39.        if (len <= 0) {//如果len小于0 说明出错。如果用json_encode处理GBK的编码,就会在这里挂掉。 

40.                if (utf16) { 

41.                        efree(utf16); 

42.                } 

43.                if (len < 0) { 

44.                        JSON_G(error_code) = PHP_JSON_ERROR_UTF8; 

45.                        if (!PG(display_errors)) { 

46.                                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid UTF-8 sequence in argument"); 

47.                        } 

48.                        smart_str_appendl(buf, "null", 4); 

49.                } else { 

50.                        smart_str_appendl(buf, "\\"\\"", 2); 

51.                } 

52.                return; 

53.        } 

54.  

55.        smart_str_appendc(buf, '"'); //输入 \\" 

56.  

57.//下面这一段代码就是将一些特殊字符转义如 双引号,反斜线等等 

58.        while (pos < len) 

59.        { 

60.                us = utf16[pos++]; 

61.  

62.                switch (us) 

63.                { 

.                        case '"': 

65.                                if (options & PHP_JSON_HEX_QUOT) { 

66.                                        smart_str_appendl(buf, "\\\"", 6); 

67.                                } else { 

68.                                        smart_str_appendl(buf, "\\\\\\"", 2); 

69.                                } 

70.                                break; 

71.  

72.                        case '\\\\': 

73.                                smart_str_appendl(buf, "\\\\\\\\", 2); 

74.                                break; 

75.case '/': 

76.                                smart_str_appendl(buf, "\\\/", 2); 

77.                                break; 

78.  

79.                        case '\\b': 

80.                                smart_str_appendl(buf, "\\\\b", 2); 

81.                                break; 

82.  

83.                        case '\\f': 

84.                                smart_str_appendl(buf, "\\\\f", 2); 

85.                                break; 

86.  

87.                        case '\\n': 

88.                                smart_str_appendl(buf, "\\\\n", 2); 

.                                break; 

90.  

91.                        case '\\r': 

92.                                smart_str_appendl(buf, "\\\\r", 2); 

93.                                break; 

94.  

95.                        case '\': 

96.                                smart_str_appendl(buf, "\\\", 2); 

97.                                break; 

98.  

99.                        case '<': 

100.                                if (options & PHP_JSON_HEX_TAG) { 

101.                                        smart_str_appendl(buf, "\\\<", 6); 

102.                                } else { 

103.                                        smart_str_appendc(buf, '<'); 

104.                                } 

105.                                break; 

106.  

107.                        case '>': 

108.                                if (options & PHP_JSON_HEX_TAG) { 

109.                                        smart_str_appendl(buf, "\\\>", 6); 

110.                                } else { 

111.                                        smart_str_appendc(buf, '>'); 

112.} 

113.                                break; 

114.  

115.                        case '&': 

116.                                if (options & PHP_JSON_HEX_AMP) { 

117.                                        smart_str_appendl(buf, "\\\&", 6); 

118.                                } else { 

119.                                        smart_str_appendc(buf, '&'); 

120.                                } 

121.                                break; 

122.  

123.                        case '\\'': 

124.                                if (options & PHP_JSON_HEX_APOS) { 

125.                                        smart_str_appendl(buf, "\\\'", 6); 

126.                                } else { 

127.                                        smart_str_appendc(buf, '\\''); 

128.                                } 

129.                                break; 

130.  

131.                        default: //一直到这里,没有特殊字符就会把值append到buf中 

132.                                if (us >= ' ' && (us & 127) == us) { 

133.                                        smart_str_appendc(buf, (unsigned char) us); 

134.                                } else { 

135.                                        smart_str_appendl(buf, "\\\); 

136.                                        us = REVERSE16(us); 

137.  

138.                                        smart_str_appendc(buf, digits[us & ((1 << 4) - 1)]); 

139.                                        us >>= 4; 

140.                                        smart_str_appendc(buf, digits[us & ((1 << 4) - 1)]); 

141.                                        us >>= 4; 

142.                                        smart_str_appendc(buf, digits[us & ((1 << 4) - 1)]); 

143.                                        us >>= 4; 

144.                                        smart_str_appendc(buf, digits[us & ((1 << 4) - 1)]); 

145.                                } 

146.                                break; 

147.                } 

148.        } 

149.        smart_str_appendc(buf, '"'); //结束 双引号。 

150.        efree(utf16); 

151.} 

再来看看数组和对象,也很简单,

 

1.static void json_encode_array(smart_str *buf, zval **val, int options TSRMLS_DC) /* {{{ */ 

2.{ 

3.        int i, r; 

4.        HashTable *myht; 

5.  

6.        if (Z_TYPE_PP(val) == IS_ARRAY) { 

7.                myht = HASH_OF(*val); 

8.                r = (options & PHP_JSON_FORCE_OBJECT) ? PHP_JSON_OUTPUT_OBJECT : json_determine_array_type(val TSRMLS_CC); 

9.        } else { 

10.                myht = Z_OBJPROP_PP(val); 

11.                r = PHP_JSON_OUTPUT_OBJECT; 

12.        }    

13.  

14.        if (myht && myht->nApplyCount > 1) { 

15.                php_error_docref(NULL TSRMLS_CC, E_WARNING, "recursion detected"); 

16.                smart_str_appendl(buf, "null", 4); 

17.                return; 

18.        } 

19.//开始标签 

20.        if (r == PHP_JSON_OUTPUT_ARRAY) { 

21.                smart_str_appendc(buf, '['); 

22.        } else { 

23.                smart_str_appendc(buf, '{'); 

24.        }    

25.  

26.        i = myht ? zend_hash_num_elements(myht) : 0; 

27.  

28.        if (i > 0) 

29.        { 

30.                char *key; 

31.                zval **data; 

32.                ulong index; 

33.                uint key_len; 

34.                HashPosition pos; 

35.                HashTable *tmp_ht; 

36.                int need_comma = 0; 

37.  

38.                zend_hash_internal_pointer_reset_ex(myht, &pos); 

39.//便利哈希表 

40.                for (;; zend_hash_move_forward_ex(myht, &pos)) { 

41.                        i = zend_hash_get_current_key_ex(myht, &key, &key_len, &index, 0, &pos); 

42.                        if (i == HASH_KEY_NON_EXISTANT) 

43.                                break; 

44.  

45.                        if (zend_hash_get_current_data_ex(myht, (void **) &data, &pos) == SUCCESS) { 

46.                                tmp_ht = HASH_OF(*data); 

47.                                if (tmp_ht) { 

48.                                        tmp_ht->nApplyCount++; 

49.                                } 

50.  

51.                                if (r == PHP_JSON_OUTPUT_ARRAY) { 

52.                                        if (need_comma) { 

53.                                                smart_str_appendc(buf, ','); 

54.                                        } else { 

55.                                                need_comma = 1; 

56.                                        } 

57.//将值append到 buf中 

58.                                        php_json_encode(buf, *data, options TSRMLS_CC); 

59.                                } else if (r == PHP_JSON_OUTPUT_OBJECT) { 

60.                                        if (i == HASH_KEY_IS_STRING) { 

61.                                                if (key[0] == '\\0' && Z_TYPE_PP(val) == IS_OBJECT) { 

62.                                                        /* Skip protected and private members. */ 

63.                                                        if (tmp_ht) { 

.                                                                tmp_ht->nApplyCount--; 

65.                                                        } 

66.                                                        continue; 

67.                                                } 

68.  

69.                                                if (need_comma) { 

70.                                                        smart_str_appendc(buf, ','); 

71.                                                } else { 

72.                                                        need_comma = 1; 

73.                                                } 

74.  

75.                                                json_escape_string(buf, key, key_len - 1, options & ~PHP_JSON_NUMERIC_CHECK TSRMLS_CC); 

76.                                                smart_str_appendc(buf, ':'); 

77.  

78.                                                php_json_encode(buf, *data, options TSRMLS_CC); 

79.                                        } else { 

80.                                                if (need_comma) { 

81.                                                        smart_str_appendc(buf, ','); 

82.                                                } else { 

83.                                                        need_comma = 1; 

84.                                                } 

85.  

86.                                                smart_str_appendc(buf, '"'); 

87.                                                smart_str_append_long(buf, (long) index); 

88.                                                smart_str_appendc(buf, '"'); 

.                                                smart_str_appendc(buf, ':'); 

90.  

91.                                                php_json_encode(buf, *data, options TSRMLS_CC); 

92.                                        } 

93.                                } 

94.  

95.                                if (tmp_ht) { 

96.                                        tmp_ht->nApplyCount--; 

97.                                } 

98.                        } 

99.                } 

100.        } 

101.//结束标签 

102.        if (r == PHP_JSON_OUTPUT_ARRAY) { 

103.                smart_str_appendc(buf, ']'); 

104.        } else { 

105.                smart_str_appendc(buf, '}'); 

106.        } 

107.} 

通过简单分析,证明了一个问题,跟我上面用sprintf的方法其实是一样的,都是拼接字符串,

而且 为了性能,更应该鼓励用sprintf来拼接json格式,

因为 json_encode会进行很多 循环操作,而且所消耗的性能是线性的 O(n)。

本文由http://www.focustar.net 整理分享。 

文档

PHP的json_encode分析

PHP的json_encode分析json的优点就不说了,有个习惯,我在输出json的时候,喜欢用sprintf拼成json格式,前两天被朋友说不标准,必须要用json_encode生成的才是标准的json格式,我当然很郁闷啦,用了这么多年了,刚知道这样做不标准,既然说我不标准,那上面才是标准的json格式? 1.{a : 'abc'} 2.{'a' : 'abc'} 3.{a : "abc"} 4.{"a" : "abc"} 那都知道,只有第四种才是标准的json格式。我这么做 1.$ret
推荐度:
  • 热门焦点

最新推荐

猜你喜欢

热门推荐

专题
Top