您好,欢迎来到三六零分类信息网!老站,搜索引擎当天收录,欢迎发信息

PHP的json_encode分析_PHP教程

2024/3/16 22:32:21发布37次查看
json的优点就不说了,
有个习惯,我在输出json的时候,喜欢用 sprintf 拼成json格式,
前两天被朋友说不标准,必须要用json_encode生成的才是标准的json格式,我当然很郁闷啦,
用了这么多年了,刚知道 这样做不标准,既然说我不标准,那上面才是标准的json格式?
{a : 'abc'} 
{'a' : 'abc'} 
{a : abc} 
{a : abc} 
那都知道,只有第四种才是标准的json格式。
我这么做
$ret_json='{%s:%s}'; 
echo json_encode($ret_json,a,abc); 
必然也符合标准。
既然如此,那我就要刨根问底,json_encode生成的json格式究竟有什么不同?
上代码
static php_function(json_encode) 

        zval *parameter; 
        smart_str buf = {0}; 
        long options = 0;
if (zend_parse_parameters(zend_num_args() tsrmls_cc, z|l, ¶meter, &options) == failure) { 
                return; 
        }
json_g(error_code) = php_json_error_none;
php_json_encode(&buf, parameter, options tsrmls_cc);
zval_stringl(return_value, buf.c, buf.len, 1);
smart_str_free(&buf); 
}
json_g(error_code) = php_json_error_none;
是定义的json错误,该错误可以通过json_last_error函数获取,你用过吗?反正我没用过。
php_json_encode是主要的操作
php_json_api void php_json_encode(smart_str *buf, zval *val, int options tsrmls_dc) /* {{{ */ 

        switch (z_type_p(val)) 
        { 
                case is_null: 
                        smart_str_appendl(buf, null, 4); //输出null 
                        break;
case is_bool: 
                        if (z_bval_p(val)) { 
                                smart_str_appendl(buf, true, 4);//输出true 
                        } else { 
                                smart_str_appendl(buf, false, 5);//输出false 
                        } 
                        break;
case is_long: 
                        smart_str_append_long(buf, z_lval_p(val));//输出长整形的值 
                        break;
case is_double: 
                        { 
                                char *d = null; 
                                int len; 
                                double dbl = z_dval_p(val);
if (!zend_isinf(dbl) && !zend_isnan(dbl)) {//非无穷尽 
                                        len = spprintf(&d, 0, %.*k, (int) eg(precision), dbl); 
                                        smart_str_appendl(buf, d, len); 
                                        efree(d); 
                                } else { 
                                        php_error_docref(null tsrmls_cc, e_warning, double %.9g does not conform to the json spec, encoded as 0, dbl); 
                                        smart_str_appendc(buf, '0'); 
                                } 
                       } 
                        break;
case is_string://字符串 
                        json_escape_string(buf, z_strval_p(val), z_strlen_p(val), options tsrmls_cc); 
                        break;
case is_array://数组和对象 
                case is_object: 
                        json_encode_array(buf, &val, options tsrmls_cc); 
                        break;
default: 
                        php_error_docref(null tsrmls_cc, e_warning, type is unsupported, encoded as null); 
                        smart_str_appendl(buf, null, 4); 
                        break; 
        }
return; 

很明显,根据不同的类型,会有相应的case。
最复杂的是 字符串 、数组 、对象这三种类型,数组和对象是同一种操作。
先看看字符串吧,很长,注释直接写在代码里。
//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.虽然我没用过。。。 
static void json_escape_string(smart_str *buf, char *s, int len, int options tsrmls_dc) /* {{{ */ 

        int pos = 0; 
        unsigned short us; 
        unsigned short *utf16;
if (len == 0) {//如果长度为0,则直接返回 双引号  
                smart_str_appendl(buf, \\, 2); 
                return; 
        }
if (options & php_json_numeric_check) {//检测是否为0-9的数字,如果是数字,那么就会直接把数据作为long或double类型返回。 
                double d; 
                int type; 
                long p;
if ((type = is_numeric_string(s, len, &p, &d, 0)) != 0) { 
                        if (type == is_long) { 
                                smart_str_append_long(buf, p); 
                        } else if (type == is_double) { 
                                if (!zend_isinf(d) && !zend_isnan(d)) { 
                                        char *tmp; 
                                        int l = spprintf(&tmp, 0, %.*k, (int) eg(precision), d); 
                                        smart_str_appendl(buf, tmp, l); 
                                        efree(tmp); 
                                } else { 
                                        php_error_docref(null tsrmls_cc, e_warning, double %.9g does not conform to the json spec, encoded as 0, d); 
                                        smart_str_appendc(buf, '0'); 
                                } 
                        } 
                        return; 
                }
}
utf16 = (unsigned short *) safe_emalloc(len, sizeof(unsigned short), 0); 
        len = utf8_to_utf16(utf16, s, len); //这里会对你输入的值一次处理转成对应的dec码,比如1是49,a是97这样的,保存到utf16中。 
        if (len                 if (utf16) { 
                        efree(utf16); 
                } 
                if (len                         json_g(error_code) = php_json_error_utf8; 
                        if (!pg(display_errors)) { 
                                php_error_docref(null tsrmls_cc, e_warning, invalid utf-8 sequence in argument); 
                        } 
                        smart_str_appendl(buf, null, 4); 
                } else { 
                        smart_str_appendl(buf, \\, 2); 
                } 
                return; 
        }
smart_str_appendc(buf, ''); //输入 \
//下面这一段代码就是将一些特殊字符转义如 双引号,反斜线等等 
        while (pos         { 
                us = utf16[pos++];
switch (us) 
                { 
                        case '': 
                                if (options & php_json_hex_quot) { 
                                        smart_str_appendl(buf, \\u0022, 6); 
                                } else { 
                                        smart_str_appendl(buf, \\\, 2); 
                                } 
                                break;
case '\\': 
                                smart_str_appendl(buf, \\\\, 2); 
                                break; 
case '/': 
                                smart_str_appendl(buf, \\/, 2); 
                                break;
case '\b': 
                                smart_str_appendl(buf, \\b, 2); 
                                break;
case '\f': 
                                smart_str_appendl(buf, \\f, 2); 
                                break;
case '\n': 
                                smart_str_appendl(buf, \\n, 2); 
                                break;
case '\r': 
                                smart_str_appendl(buf, \\r, 2); 
                                break;
case '\t': 
                                smart_str_appendl(buf, \\t, 2); 
                                break;
case '                                if (options & php_json_hex_tag) { 
                                        smart_str_appendl(buf, \\u003c, 6); 
                                } else { 
                                        smart_str_appendc(buf, '                                } 
                                break;
case '>': 
                                if (options & php_json_hex_tag) { 
                                        smart_str_appendl(buf, \\u003e, 6); 
                                } else { 
                                        smart_str_appendc(buf, '>'); 

                                break;
case '&': 
                                if (options & php_json_hex_amp) { 
                                        smart_str_appendl(buf, \\u0026, 6); 
                                } else { 
                                        smart_str_appendc(buf, '&'); 
                                } 
                                break;
case '\'': 
                                if (options & php_json_hex_apos) { 
                                        smart_str_appendl(buf, \\u0027, 6); 
                                } else { 
                                        smart_str_appendc(buf, '\''); 
                                } 
                                break;
default: //一直到这里,没有特殊字符就会把值append到buf中 
                                if (us >= ' ' && (us & 127) == us) { 
                                        smart_str_appendc(buf, (unsigned char) us); 
                                } else { 
                                        smart_str_appendl(buf, \\u, 2); 
                                        us = reverse16(us);
smart_str_appendc(buf, digits[us & ((1                                         us >>= 4; 
                                        smart_str_appendc(buf, digits[us & ((1                                         us >>= 4; 
                                        smart_str_appendc(buf, digits[us & ((1                                         us >>= 4; 
                                        smart_str_appendc(buf, digits[us & ((1                                 } 
                                break; 
                } 
        } 
        smart_str_appendc(buf, ''); //结束 双引号。 
        efree(utf16); 

再来看看数组和对象,也很简单,
static void json_encode_array(smart_str *buf, zval **val, int options tsrmls_dc) /* {{{ */ 

        int i, r; 
        hashtable *myht;
if (z_type_pp(val) == is_array) { 
                myht = hash_of(*val); 
                r = (options & php_json_force_object) ? php_json_output_object : json_determine_array_type(val tsrmls_cc); 
        } else { 
                myht = z_objprop_pp(val); 
                r = php_json_output_object; 
        }
if (myht && myht->napplycount > 1) { 
                php_error_docref(null tsrmls_cc, e_warning, recursion detected); 
                smart_str_appendl(buf, null, 4); 
                return; 
        } 
//开始标签 
        if (r == php_json_output_array) { 
                smart_str_appendc(buf, '['); 
        } else { 
                smart_str_appendc(buf, '{'); 
        }
i = myht ? zend_hash_num_elements(myht) : 0;
if (i > 0) 
        { 
                char *key; 
                zval **data; 
                ulong index; 
                uint key_len; 
                hashposition pos; 
                hashtable *tmp_ht; 
                int need_comma = 0;
zend_hash_internal_pointer_reset_ex(myht, &pos); 
//便利哈希表 
                for (;; zend_hash_move_forward_ex(myht, &pos)) { 
                        i = zend_hash_get_current_key_ex(myht, &key, &key_len, &index, 0, &pos); 
                        if (i == hash_key_non_existant) 
                                break;
if (zend_hash_get_current_data_ex(myht, (void **) &data, &pos) == success) { 
                                tmp_ht = hash_of(*data); 
                                if (tmp_ht) { 
                                        tmp_ht->napplycount++; 
                                }
if (r == php_json_output_array) { 
                                        if (need_comma) { 
                                                smart_str_appendc(buf, ','); 
                                        } else { 
                                                need_comma = 1; 
                                        } 
//将值append到 buf中 
                                        php_json_encode(buf, *data, options tsrmls_cc); 
                                } else if (r == php_json_output_object) { 
                                        if (i == hash_key_is_string) { 
                                                if (key[0] == '\0' && z_type_pp(val) == is_object) { 
                                                        /* skip protected and private members. */ 
                                                        if (tmp_ht) { 
                                                                tmp_ht->napplycount--; 
                                                        } 
                                                        continue; 
                                                }
if (need_comma) { 
                                                        smart_str_appendc(buf, ','); 
                                                } else { 
                                                        need_comma = 1; 
                                                }
json_escape_string(buf, key, key_len - 1, options & ~php_json_numeric_check tsrmls_cc); 
                                                smart_str_appendc(buf, ':');
php_json_encode(buf, *data, options tsrmls_cc); 
                                        } else { 
                                                if (need_comma) { 
                                                        smart_str_appendc(buf, ','); 
                                                } else { 
                                                        need_comma = 1; 
                                                }
smart_str_appendc(buf, ''); 
                                                smart_str_append_long(buf, (long) index); 
                                                smart_str_appendc(buf, ''); 
                                                smart_str_appendc(buf, ':');
php_json_encode(buf, *data, options tsrmls_cc); 
                                        } 
                                }
if (tmp_ht) { 
                                        tmp_ht->napplycount--; 
                                } 
                        } 
                } 
        } 
//结束标签 
        if (r == php_json_output_array) { 
                smart_str_appendc(buf, ']'); 
        } else { 
                smart_str_appendc(buf, '}'); 
        } 

通过简单分析,证明了一个问题,跟我上面用sprintf的方法其实是一样的,都是拼接字符串,
http://www.bkjia.com/phpjc/477721.htmlwww.bkjia.comtruehttp://www.bkjia.com/phpjc/477721.htmltecharticlejson的优点就不说了, 有个习惯,我在输出json的时候,喜欢用 sprintf 拼成json格式, 前两天被朋友说不标准,必须要用json_encode生成的才是标...
该用户其它信息

VIP推荐

免费发布信息,免费发布B2B信息网站平台 - 三六零分类信息网 沪ICP备09012988号-2
企业名录 Product