[source] 深入理解PHP源代碼JSON解析

https://github.com/openparallel/php-src/blob/6025d2973786ac5be80bcd7d276274d46fab3add/ext/json/json.c

json_c.png

1 主題

主要從源碼角度分析php的 json_encode && json_decode
php版本: 5.5.23

2 基本概念

首先,json串的 key必須是字符串 , int類型的key會(huì)被轉(zhuǎn)換成字符串
如果傳入的是浮點(diǎn)數(shù),則會(huì)被取整,變成字符串,或者key 為數(shù)組之類的,則該key會(huì)被過濾

其次,php的json函數(shù)只支持utf字符,不支持gbk字符

3 json_encode

php源碼的實(shí)現(xiàn)其實(shí)很簡(jiǎn)單,就是 遍歷傳入的參數(shù)(一般是array),找出 key && value,拼接成字符串

3.1 Description

函數(shù)的原型如下,有兩個(gè)可選參數(shù)

  1. string json_encode ( mixed $value [, int $options = 0 [, int $depth = 512 ]] )
    value : 這個(gè)就是要進(jìn)行encode的參數(shù),支持任何類型的變量,一般是數(shù)組
    depth : 限制最大的層數(shù)
    options : 一些特殊需求,比如可以設(shè)置是否對(duì)某些特殊字符進(jìn)行特殊編碼
  • JSON_HEX_AMP : 在encode的時(shí)候把 & 變成 \u0026
  • JSON_HEX_APOS : 在encode的時(shí)候把 ' 變成 \u0027
  • JSON_HEX_QUOT : 在encode的時(shí)候把 " 變成 \u0022
  • JSON_FORCE_OBJECT : 強(qiáng)制輸出為object形式,針對(duì)非關(guān)聯(lián)數(shù)組的時(shí)候
    比如 arr = array(‘x’) , json_encode(arr) => [“x”], json_encode($arr, JSON_FORCE_OBJECT ) => {“0”:”x”}
  • JSON_NUMERIC_CHECK : 在encode 的時(shí)候,把整數(shù)字符串變成整數(shù)
  • JSON_PRETTY_PRINT : 使輸出的json串更可讀
  • JSON_UNESCAPED_SLASHES : 不對(duì) / 進(jìn)行轉(zhuǎn)義
  • JSON_UNESCAPED_UNICODE : 使多字節(jié)更可讀,默認(rèn)是轉(zhuǎn)換成 \uXXXX
  • JSON_PRESERVE_ZERO_FRACTION : 確保浮點(diǎn)數(shù)被encode成浮點(diǎn)數(shù),這個(gè)選項(xiàng)在5.6.6里才被添加
    例如: json_encode(12.0) => 12, json_encode(12.0, JSON_PRESERVE_ZERO_FRACTION) => 12.0

3.2 源碼

3.2.1 主體

json_encode的入口很簡(jiǎn)單,接受三個(gè)參數(shù),然后調(diào)用 php_json_encode 進(jìn)行處理,結(jié)果存儲(chǔ)在 buf 里, php自己封裝了一套字符串處理的函數(shù)

static PHP_FUNCTION(json_encode)
    {
        zval* parameter;
        smart_str buf = {0};
        long options = 0;
        long depth = JSON_PARSER_DEFAULT_DEPTH;
        //step1 取參數(shù)
        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|ll", &parameter, &options, &depth) == FAILURE) {
            return;
        }
 
        JSON_G(error_code) = PHP_JSON_ERROR_NONE;
 
        JSON_G(encode_max_depth) = depth;
 
        //step2 調(diào)用處理函數(shù)
        php_json_encode(&buf, parameter, options TSRMLS_CC);
 
        //step3 設(shè)置返回的內(nèi)容
        if (JSON_G(error_code) != PHP_JSON_ERROR_NONE && !(options & PHP_JSON_PARTIAL_OUTPUT_ON_ERROR)) {
            ZVAL_FALSE(return_value);
        } else {
            ZVAL_STRINGL(return_value, buf.c, buf.len, 1);
        }
 
        smart_str_free(&buf);
    }

3.2.2 主要處理流程

php_json_encode 里主要是根據(jù)輸入?yún)?shù) val的類型 進(jìn)行處理,并把結(jié)果 append到buf 里,具體有這么幾種情況:

  • 對(duì) NULL BOOL LONG 的處理比較簡(jiǎn)單,直接轉(zhuǎn)換成相應(yīng)的字符串a(chǎn)ppend到buf里

  • 對(duì) DOUBLE 浮點(diǎn)數(shù)類型的,會(huì) 判斷是否越界,同時(shí)還會(huì)截?cái)嗳∏懊鍱G(precision)位 , precision 在php.ini里可以設(shè)置,默認(rèn)是14位

  • 對(duì) STRING 字符串類型的,會(huì)調(diào)用 json_escape_string 進(jìn)行處理,比如加轉(zhuǎn)義字符,特殊字符是否需要替換之類的

  • 對(duì) OBJECT 這種對(duì)象類型的,會(huì)先判斷一下該對(duì)象是否 implementsJsonSerializable 這個(gè)抽象類,并重載了 jsonSerialize 函數(shù)

    如果是的話,則調(diào)用類自定義的 jsonSerialize 函數(shù)進(jìn)行encode,否則調(diào)用 jsonencode_array 進(jìn)行處理,具體可以參考 中文版 <[http://www.laruence.com/2011/10/10/2204.html](http://www.laruence.com/2011/10/10/2204.html)> 或者 英文版 <[http://schlueters.de/blog/archives/135-Jason,-let-me-help-you!.html](http://schlueters.de/blog/archives/135-Jason,-let-me-help-you!.html)>_ 里關(guān)于 JsonSerializable接口 的介紹,這個(gè)是5.4才加入的新功能

  • 對(duì) ARRAY 這種數(shù)組類型的,則會(huì)調(diào)用 json_encode_array 進(jìn)行處理,在 jsonencode_array 里會(huì)遍歷數(shù)組,先插入 array 的key,然后再插入value(其實(shí)是通過調(diào)用php_json_encode,相互遞歸調(diào)用--||)

PHP_JSON_API void php_json_encode(smart_str* buf, zval* val, int options TSRMLS_DC)
   {
       switch (Z_TYPE_P(val))
       {
           case IS_NULL: //NULL 類型
               smart_str_appendl(buf, "null", 4);
               break;
 
           case IS_BOOL: //BOOL 類型
               if (Z_BVAL_P(val)) {
                   smart_str_appendl(buf, "true", 4);
               } else {
                   smart_str_appendl(buf, "false", 5);
               }
               break;
 
           case IS_LONG: //整數(shù)
               smart_str_append_long(buf, Z_LVAL_P(val));
               break;
 
           case IS_DOUBLE: //浮點(diǎn)數(shù)
               {
                   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 {
                       JSON_G(error_code) = PHP_JSON_ERROR_INF_OR_NAN;
                       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_OBJECT: //對(duì)象類型,先判斷類是否implements了JsonSerializable這個(gè)抽象類,并重載了jsonSerialize函數(shù)
               if (instanceof_function(Z_OBJCE_P(val), php_json_serializable_ce TSRMLS_CC)) {
                   json_encode_serializable_object(buf, val, options TSRMLS_CC); //使用對(duì)象的 jsonSerialize函數(shù) 進(jìn)行encode
                   break;
               }
               //沒有定義的話,則調(diào)用 json_encode_array 函數(shù) encode 這個(gè)對(duì)象
               // fallthrough -- Non-serializable object
           case IS_ARRAY: //數(shù)組對(duì)象
               json_encode_array(buf, &val, options TSRMLS_CC);
               break;
 
           default: //出錯(cuò)
               JSON_G(error_code) = PHP_JSON_ERROR_UNSUPPORTED_TYPE;
               smart_str_appendl(buf, "null", 4);
               break;
       }
 
       return;
   }

3.2.3 對(duì)對(duì)象的處理

之前也說了,對(duì) OBJECT 這種對(duì)象類型的,會(huì)先判斷一下該對(duì)象是否 implementsJsonSerializable 這個(gè)抽象類,并重載了 jsonSerialize 函數(shù)

如果是的話,則調(diào)用類自定義的 jsonSerialize 函數(shù)進(jìn)行encode,否則調(diào)用 json_encode_array 進(jìn)行處理

具體細(xì)節(jié)可以參考 中文版 <[http://www.laruence.com/2011/10/10/2204.html](http://www.laruence.com/2011/10/10/2204.html)>* 或者 英文版 <[http://schlueters.de/blog/archives/135-Jason,-let-me-help-you!.html](http://schlueters.de/blog/archives/135-Jason,-let-me-help-you!.html)>* 里關(guān)于 JsonSerializable接口 的介紹,這個(gè)是5.4才加入的新功能

再?gòu)脑创a角度看看是如何調(diào)用對(duì)象自定義的 jsonSerialize 函數(shù)的

static void json_encode_serializable_object(smart_str* buf, zval* val, int options TSRMLS_DC)
    {   
      zend_class_entry* ce = Z_OBJCE_P(val);
      zval * retval = NULL, fname;   
      HashTable* myht;
 
      if (Z_TYPE_P(val) == IS_ARRAY) {
          myht = HASH_OF(val);
      } else {
          myht = Z_OBJPROP_P(val);      
      }
 
      if (myht && myht->nApplyCount > 1) {
          JSON_G(error_code) = PHP_JSON_ERROR_RECURSION;
          smart_str_appendl(buf, "null", 4);
          return;
      }
 
      ZVAL_STRING(&fname, "jsonSerialize", 0);
 
      //調(diào)用 jsonSerialize 函數(shù) 
      if (FAILURE == call_user_function_ex(EG(function_table), &val, &fname, &retval, 0, NULL, 1, NULL TSRMLS_CC) || !retval) {
          zend_throw_exception_ex(NULL, 0 TSRMLS_CC, "Failed calling %s::jsonSerialize()", ce->name);
          smart_str_appendl(buf, "null", sizeof("null") - 1);
          return;
      }
 
      if (EG(exception)) {//調(diào)用中是否拋異常
          // Error already raised  
          zval_ptr_dtor(&retval);       
          smart_str_appendl(buf, "null", sizeof("null") - 1);
          return;
      }
 
      if ((Z_TYPE_P(retval) == IS_OBJECT) &&
          (Z_OBJ_HANDLE_P(retval) == Z_OBJ_HANDLE_P(val))) { //如果返回的是一個(gè)對(duì)象,同時(shí)返回結(jié)果還是要encode的對(duì)象,則直接調(diào)用 json_encode_array 進(jìn)行處理
          // Handle the case where jsonSerialize does: return $this; by going straight to encode array
          json_encode_array(buf, &retval, options TSRMLS_CC);
      } else {
          // All other types, encode as normal
          php_json_encode(buf, retval, options TSRMLS_CC);//否則繼續(xù)調(diào)用 php_json_encode 遞歸處理
      }
 
      zval_ptr_dtor(&retval);
    }

3.2.4 對(duì)數(shù)組的處理

我們?cè)賮砜匆幌氯绾螌?duì)數(shù)組進(jìn)行encode

之前也說過了對(duì) ARRAY 這種數(shù)組類型的,則會(huì)調(diào)用 json_encode_array 進(jìn)行處理,在 json_encode_array 里會(huì)遍歷數(shù)組,先插入 array 的key,然后再插入value(其實(shí)是通過調(diào)用php_json_encode,相互遞歸調(diào)用)

具體實(shí)現(xiàn)上有兩個(gè)步驟

首先判斷一下是以對(duì)象形式(k1:v1, k2:v2…)輸出,還是以數(shù)組形式輸出(k1,k2…)

如果val的類型非數(shù)組,則以對(duì)象形式輸出
否則如果val的類型是數(shù)組,看一下 options 參數(shù)是否有設(shè)置強(qiáng)制以對(duì)象形式輸出
如果沒有的話,則要看val的內(nèi)容判斷了,通過 json_determine_array_type 函數(shù)進(jìn)行判斷,判斷val是否是關(guān)聯(lián)性數(shù)組
遍歷數(shù)組,根據(jù)以對(duì)象形式輸出還是數(shù)組形式輸出進(jìn)行處理

以數(shù)組形式輸出,插入分隔符 , ,然后調(diào)用 php_json_encode 插入value
以對(duì)象形式輸出,插入key(如果key非字符串,則強(qiáng)制轉(zhuǎn)換為整數(shù)( 如果key非字符串,非整數(shù),那么呵呵 ),再轉(zhuǎn)換為字符串插入),然后調(diào)用 php_json_encode 插入value

static void json_encode_array(smart_str* buf, zval** val, int options TSRMLS_DC)
    {
        //判斷是以對(duì)象形式(k1:v1, k2:v2...)輸出,還是以數(shù)組形式輸出(k1,k2...)
        if (Z_TYPE_PP(val) == IS_ARRAY) {
            r = (options & PHP_JSON_FORCE_OBJECT) ? PHP_JSON_OUTPUT_OBJECT : json_determine_array_type(val TSRMLS_CC);
        } else {
            r = PHP_JSON_OUTPUT_OBJECT;
        }
        //..........................
        //循環(huán)處理每個(gè)key && value
        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_EXISTENT)
                break;
 
            if (zend_hash_get_current_data_ex(myht, (void ** ) &data, &pos) == SUCCESS) {
                if (r == PHP_JSON_OUTPUT_ARRAY) { //以數(shù)組形式輸出,不需要插入key,直接調(diào)用php_json_encode插入value
                    //..................
                    php_json_encode(buf, * data, options TSRMLS_CC); //數(shù)組形式,沒有key(其實(shí)是0,1,2這種數(shù)字),則直接調(diào)用 php_json_encode插入value
                } else if (r == PHP_JSON_OUTPUT_OBJECT) { //以對(duì)象形式輸出,先插入key(對(duì)key是否為string做一些處理),然后調(diào)用php_json_encode插入value
                    if (i == HASH_KEY_IS_STRING) { //如果key為字符串類型的,則直接插入
                        //..................
                        json_escape_string(buf, key, key_len - 1, options & ~PHP_JSON_NUMERIC_CHECK TSRMLS_CC);//插入key
                        //..................
                        php_json_encode(buf, * data, options TSRMLS_CC);//調(diào)用php_json_encode插入value
                    } else {
                        //..................
                        smart_str_append_long(buf, (long) index);//把key轉(zhuǎn)換為long,再轉(zhuǎn)換為string類型的,然后插入,但是如果key非字符串,非整數(shù),那么呵呵
                        //..................
                        php_json_encode(buf, * data, options TSRMLS_CC);//調(diào)用php_json_encode插入value
                    }
                }
            }
        }
        //..................
    }

記得以前有一個(gè)題目,就是給定一個(gè)array,從php代碼上怎么判斷是關(guān)聯(lián)型的還是非關(guān)聯(lián)型的
http://stackoverflow.com/questions/173400/how-to-check-if-php-array-is-associative-or-sequential
再來看一下php內(nèi)部是怎么判斷一個(gè)數(shù)組是關(guān)聯(lián)型的還是非關(guān)聯(lián)型的
做法其實(shí)也是一樣的,遍歷每個(gè)key,判斷是否等于對(duì)應(yīng)的下標(biāo)

static int json_determine_array_type(zval** val TSRMLS_DC)
{
    int i;
    HashTable* myht = HASH_OF(* val);
 
    i = myht ? zend_hash_num_elements(myht) : 0;
    if (i > 0) {
        char* key;
        ulong index, idx;
        uint key_len;
        HashPosition pos;
 
        zend_hash_internal_pointer_reset_ex(myht, &pos);
        idx = 0;
        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_EXISTENT) {
                break;
            }
 
            if (i == HASH_KEY_IS_STRING) {
                return 1;
            } else {
                if (index != idx) {
                    return 1;
                }
            }
            idx++;
        }
    }
 
    return PHP_JSON_OUTPUT_ARRAY;
}

4 json_decode

4.1 Description

函數(shù)的原型如下,有兩個(gè)可選參數(shù)

mixed json_decode ( string json [, boolassoc = false [, int depth = 512 [, intoptions = 0 ]]] )
json : 這個(gè)就是要進(jìn)行decode的json字符串
assoc : 當(dāng)該參數(shù)為 true 時(shí),將返回 array 而非 object
depth : 遞歸處理的層數(shù)
options : 一些特殊需求,目前只有一個(gè)
JSON_BIGINT_AS_STRING : 當(dāng)value是大整數(shù)的時(shí)候,如果設(shè)置了這個(gè)選項(xiàng),則> value的類型是字符串,避免精度缺失,默認(rèn)是浮點(diǎn)數(shù)
json = '12345678901234567890'; var_dump(json_decode(json));
var_dump(json_decode($json, false, 512, JSON_BIGINT_AS_STRING));
輸出為::
float(1.2345678901235E+19)
string(20) "12345678901234567890"

4.2 源碼

4.2.1 主體

json_decode主函數(shù),其實(shí)就接受四個(gè)參數(shù),然后調(diào)用 php_json_decode_ex 進(jìn)行處理

static PHP_FUNCTION(json_decode) { 
        char * str;
        int str_len;
       zend_bool assoc = 0; // return JS objects as PHP objects by default
        long depth = JSON_PARSER_DEFAULT_DEPTH;
        long options = 0; 
        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|bll", &str,&str_len, &assoc, &depth, &options) == FAILURE) {
              return;
        }
       JSON_G(error_code) = 0;
        if (!str_len) {
              RETURN_NULL();
        }
        // For BC reasons, the bool $assoc overrides the long $options bit for        PHP_JSON_OBJECT_AS_ARRAY
        if (assoc) {
              options ||= PHP_JSON_OBJECT_AS_ARRAY;
        } else {
              options &= ~PHP_JSON_OBJECT_AS_ARRAY;
        }
       php_json_decode_ex(return_value, str, str_len, options, depth TSRMLS_CC);
 }

讓我們來看看在 php_json_decode_ex 里都做了什么事情
其實(shí)主要包括三個(gè)步驟

  1. 判斷是否為utf8編碼,如果是的話,同時(shí)轉(zhuǎn)換為utf16
  2. 先調(diào)用 parse_JSON_ex 去解析這個(gè)json串,這個(gè)是整個(gè)解析的核心部分
  3. 如果失敗,則盡量而為去解析這個(gè)非標(biāo)準(zhǔn)的json串
PHP_JSON_API void php_json_decode_ex(zval * return_value, char * str, int str_len, int options, long depth TSRMLS_DC)
 {
         int utf16_len;
        zval * z;
         unsigned short * utf16;
        JSON_parser jp;
         //step1 判斷是否是utf8字符
        utf16 = (unsigned short * ) safe_emalloc((str_len+1), sizeof(unsigned short), 1);
        utf16_len = json_utf8_to_utf16(utf16, str, str_len);
         //...........
        ALLOC_INIT_ZVAL(z);
        jp = new_JSON_parser(depth);
         //step2 進(jìn)行處理
         if (parse_JSON_ex(jp, z, utf16, utf16_len, options TSRMLS_CC)) {
                 * return_value = * z;
         }
         else //step3 對(duì)一些不規(guī)范的json串,盡力而為去decode,比如輸入的字符串是一個(gè)整數(shù),兩邊沒有被 " 包含
         {
                 //去掉左右兩邊多余的 空格 table 換行 回車
                 //.......
                RETVAL_NULL();
                 //處理NULL or BOOL類型
                 if (trim_len == 4) {
                         if (!strncasecmp(trim, "null", trim_len)) {
                                jp->error_code = PHP_JSON_ERROR_NONE;
                                RETVAL_NULL();
                         } else if (!strncasecmp(trim, "true", trim_len)) {
                                RETVAL_BOOL(1);
                         }
                 } else if (trim_len == 5 && !strncasecmp(trim, "false", trim_len)) {
                        RETVAL_BOOL(0);
                 }
                 //處理數(shù)字
                 if ((type = is_numeric_string_ex(trim, trim_len, &p, &d, 0, &overflow_info)) != 0) {
                         if (type == IS_LONG) {
                                RETVAL_LONG(p); //返回整數(shù)
                         } else if (type == IS_DOUBLE) { //返回浮點(diǎn)數(shù)
                                 //.......
                         }
                 }
                 //返回錯(cuò)誤
                 if (Z_TYPE_P(return_value) != IS_NULL) {
                        jp->error_code = PHP_JSON_ERROR_NONE;
                 }
                zval_dtor(z);
         }
        FREE_ZVAL(z);
        efree(utf16);
        JSON_G(error_code) = jp->error_code;
        free_JSON_parser(jp);
 }

4.2.2 json解析器

來看看php是如何解析json串的

首先來看看解析的時(shí)候,需要用到的這個(gè)結(jié)構(gòu)體

  1. typedef struct JSON_parser_struct {
  2. int state; //當(dāng)前的狀態(tài)
  3. int depth; //最大的深度
  4. int top; //當(dāng)前處于第幾層
  5. int error_code; //錯(cuò)誤碼
  6. int* stack; //記錄每一層正在解析的狀態(tài),取值有MODE_ARRAY, MODE_DONE, MODE_KEY, MODE_OBJECT
  7. zval ** the_zstack; //記錄每一層正在decode中的值的stack,如果 depth 小于 JSON_PARSER_DEFAULT_DEPTH,則用 the_static_zstack,否則重新申請(qǐng)內(nèi)存
  8. zval * the_static_zstack[JSON_PARSER_DEFAULT_DEPTH]; // 默認(rèn)使用的stack
  9. } * JSON_parser;

主要是通過狀態(tài)機(jī)來處理的

int parse_JSON_ex(JSON_parser jp, zval * z, unsigned short utf16_json[], int length, int options TSRMLS_DC)
 {
     //...............
     for (the_index = 0; the_index < length; the_index += 1) {
         next_char = utf16_json[the_index];
         //....................
 
         next_state = state_transition_table[jp->state][next_class];
 
         if (next_state >= 0) {
             //...............
             //主要是獲取每個(gè)key or value的值,存儲(chǔ)在buf變量里
             jp->state = next_state;
         } else {
             //主要是處理json里的特殊標(biāo)志
             // { or [ : 一個(gè)層次的開始標(biāo)識(shí)
             // } or ] : 一個(gè)層次的結(jié)束標(biāo)志
             // " :一個(gè)字符串取值的開始或者結(jié)束標(biāo)志
             // : : 一個(gè)value的取值開始標(biāo)志,當(dāng)然這個(gè)value 可以是任何類型的
             // , : 另外一個(gè)k/v or k的開始標(biāo)志
 
             switch (next_state) {
             case -9: // empty }
                 if (!pop(jp, MODE_KEY)) {
                     FREE_BUFFERS();
                     return false;
                 }
                 jp->state = OK;
                 break;
             case -8: // } 一個(gè)層次的結(jié)束標(biāo)志
                 //...................
                 jp->state = OK;
                 break;
             case -7: // ]
             {
                 //...................
                 jp->state = OK;
             }
             break;
             case -6: // {
                 //...................
                 break;
             case -5: // [
                 //...................
                 break;
             case -4: // "
                 //...................
                 break;
             case -3: // ,
                 //...................
             break;
             case -2: // :
                 //...................
             default: //  syntax error
                 {
                     jp->error_code = PHP_JSON_ERROR_SYNTAX;
                     FREE_BUFFERS();
                     return false;
                 }
             }
         }
     }
 
     FREE_BUFFERS();
     if (jp->state == OK && pop(jp, MODE_DONE)) {
         return true;
     }
 
     jp->error_code = PHP_JSON_ERROR_SYNTAX;
     return false;
 }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 總結(jié)了一些開發(fā)中常用的函數(shù): usleep() //函數(shù)延遲代碼執(zhí)行若干微秒。 unpack() //函數(shù)從二進(jìn)制...
    ADL2022閱讀 541評(píng)論 0 3
  • php usleep() 函數(shù)延遲代碼執(zhí)行若干微秒。 unpack() 函數(shù)從二進(jìn)制字符串對(duì)數(shù)據(jù)進(jìn)行解包。 uni...
    思?jí)鬚HP閱讀 2,133評(píng)論 1 24
  • PHP常用函數(shù)大全 usleep() 函數(shù)延遲代碼執(zhí)行若干微秒。 unpack() 函數(shù)從二進(jìn)制字符串對(duì)數(shù)據(jù)進(jìn)行解...
    上街買菜丶迷倒老太閱讀 1,487評(píng)論 0 20
  • Javascript 中可以用{}表示一個(gè)對(duì)象,用[]表示一個(gè)數(shù)組,如: var obj={"a":"v","b"...
    旅行家John閱讀 1,991評(píng)論 0 3
  • 在之前我寫過php返回json數(shù)據(jù)簡(jiǎn)單實(shí)例,剛剛上網(wǎng),突然發(fā)現(xiàn)一篇文章,也是介紹json的,還挺詳細(xì),值得參考。內(nèi)...
    溢之閱讀 679評(píng)論 0 0

友情鏈接更多精彩內(nèi)容