亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 開發(fā) > PHP > 正文

PHP中array_keys和array_unique函數(shù)源碼的分析

2024-05-04 23:43:18
字體:
供稿:網(wǎng)友
本文從array_keys和array_unique的源碼分析出函數(shù)的性能,并給出了優(yōu)化建議,十分不錯的文章,有需要的小伙伴可以參考下
 

性能分析

從運行性能上分析,看看下面的測試代碼:

$test=array();for($run=0; $run<10000; $run++)$test[]=rand(0,100);$time=microtime(true);$out = array_unique($test);$time=microtime(true)-$time;echo 'Array Unique: '.$time."/n";$time=microtime(true);$out=array_keys(array_flip($test));$time=microtime(true)-$time;echo 'Keys Flip: '.$time."/n";$time=microtime(true);$out=array_flip(array_flip($test));$time=microtime(true)-$time;echo 'Flip Flip: '.$time."/n";

運行結(jié)果如下:

 

從上圖可以看到,使用array_unique函數(shù)需要0.069s;使用array_flip后再使用array_keys函數(shù)需要0.00152s;使用兩次array_flip函數(shù)需要0.00146s。

測試結(jié)果表明,使用array_flip后再調(diào)用array_keys函數(shù)比array_unique函數(shù)快。那么,具體原因是什么呢?讓我們看看在PHP底層,這兩個函數(shù)是怎么實現(xiàn)的。

源碼分析

/* {{{ proto array array_keys(array input [, mixed search_value[, bool strict]])  Return just the keys from the input array, optionally only for the specified       search_value */PHP_FUNCTION(array_keys){  //變量定義  zval *input,        /* Input array */     *search_value = NULL,  /* Value to search for */     **entry,        /* An entry in the input array */      res,          /* Result of comparison */     *new_val;        /* New value */  int  add_key;        /* Flag to indicate whether a key should be added */  char *string_key;      /* String key */  uint  string_key_len;  ulong num_key;        /* Numeric key */  zend_bool strict = 0;    /* do strict comparison */  HashPosition pos;  int (*is_equal_func)(zval *, zval *, zval * TSRMLS_DC) = is_equal_function;  //程序解析參數(shù)  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|zb", &input, &search_value, &strict) == FAILURE) {    return;  }  // 如果strict是true,則設(shè)置is_equal_func為is_identical_function,即全等比較  if (strict) {    is_equal_func = is_identical_function;  }  /* 根據(jù)search_vale初始化返回的數(shù)組大小 */  if (search_value != NULL) {    array_init(return_value);  } else {    array_init_size(return_value, zend_hash_num_elements(Z_ARRVAL_P(input)));  }  add_key = 1;  /* 遍歷輸入的數(shù)組參數(shù),然后添加鍵值到返回的數(shù)組 */  zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(input), &pos);//重置指針  //循環(huán)遍歷數(shù)組  while (zend_hash_get_current_data_ex(Z_ARRVAL_P(input), (void **)&entry, &pos) == SUCCESS) {    // 如果search_value不為空    if (search_value != NULL) {      // 判斷search_value與當(dāng)前的值是否相同,并將比較結(jié)果保存到add_key變量      is_equal_func(&res, search_value, *entry TSRMLS_CC);      add_key = zval_is_true(&res);    }    if (add_key) {      // 創(chuàng)建一個zval結(jié)構(gòu)體      MAKE_STD_ZVAL(new_val);      // 根據(jù)鍵值是字符串還是整型數(shù)字將值插入到return_value中      switch (zend_hash_get_current_key_ex(Z_ARRVAL_P(input), &string_key, &string_key_len, &num_key, 1, &pos)) {        case HASH_KEY_IS_STRING:          ZVAL_STRINGL(new_val, string_key, string_key_len - 1, 0);          // 此函數(shù)負責(zé)將值插入到return_value中,如果鍵值已存在,則使用新值更新對應(yīng)的值,否則直接插入          zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &new_val, sizeof(zval *), NULL);          break;        case HASH_KEY_IS_LONG:          Z_TYPE_P(new_val) = IS_LONG;          Z_LVAL_P(new_val) = num_key;          zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &new_val, sizeof(zval *), NULL);          break;      }    }    // 移動到下一個    zend_hash_move_forward_ex(Z_ARRVAL_P(input), &pos);  }}/* }}} */

以上是array_keys函數(shù)底層的源碼。為方便理解,筆者添加了一些中文注釋。如果需要查看原始代碼,可以點擊查看。這個函數(shù)的功能就是新建一個臨時數(shù)組,然后將鍵值對重新復(fù)制到新的數(shù)組,如果復(fù)制過程中有重復(fù)的鍵值出現(xiàn),那么就用新的值替換。這個函數(shù)的主要步驟是地57和63行調(diào)用的zend_hash_next_index_insert函數(shù)。該函數(shù)將元素插入到數(shù)組中,如果出現(xiàn)重復(fù)的值,則使用新的值更新原鍵值指向的值,否則直接插入,時間復(fù)雜度是O(n)。

/* {{{ proto array array_flip(array input)  Return array with key <-> value flipped */PHP_FUNCTION(array_flip){  // 定義變量  zval *array, **entry, *data;  char *string_key;  uint str_key_len;  ulong num_key;  HashPosition pos;  // 解析數(shù)組參數(shù)  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &array) == FAILURE) {    return;  }  // 初始化返回數(shù)組  array_init_size(return_value, zend_hash_num_elements(Z_ARRVAL_P(array)));  // 重置指針  zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(array), &pos);  // 遍歷每個元素,并執(zhí)行鍵<->值交換操作  while (zend_hash_get_current_data_ex(Z_ARRVAL_P(array), (void **)&entry, &pos) == SUCCESS) {    // 初始化一個結(jié)構(gòu)體    MAKE_STD_ZVAL(data);    // 將原數(shù)組的值賦值為新數(shù)組的鍵    switch (zend_hash_get_current_key_ex(Z_ARRVAL_P(array), &string_key, &str_key_len, &num_key, 1, &pos)) {      case HASH_KEY_IS_STRING:        ZVAL_STRINGL(data, string_key, str_key_len - 1, 0);        break;      case HASH_KEY_IS_LONG:        Z_TYPE_P(data) = IS_LONG;        Z_LVAL_P(data) = num_key;        break;    }    // 將原數(shù)組的鍵賦值為新數(shù)組的值,如果有重復(fù)的,則使用新值覆蓋舊值    if (Z_TYPE_PP(entry) == IS_LONG) {      zend_hash_index_update(Z_ARRVAL_P(return_value), Z_LVAL_PP(entry), &data, sizeof(data), NULL);    } else if (Z_TYPE_PP(entry) == IS_STRING) {      zend_symtable_update(Z_ARRVAL_P(return_value), Z_STRVAL_PP(entry), Z_STRLEN_PP(entry) + 1, &data, sizeof(data), NULL);    } else {      zval_ptr_dtor(&data); /* will free also zval structure */      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Can only flip STRING and INTEGER values!");    }    // 下一個    zend_hash_move_forward_ex(Z_ARRVAL_P(array), &pos);  }}/* }}} */

上面就是是array_flip函數(shù)的源碼。點擊鏈接查看原始代碼。這個函數(shù)主要的做的事情就是創(chuàng)建一個新的數(shù)組,遍歷原數(shù)組。在26行開始將原數(shù)組的值賦值為新數(shù)組的鍵,然后在37行開始將原數(shù)組的鍵賦值為新數(shù)組的值,如果有重復(fù)的,則使用新值覆蓋舊值。整個函數(shù)的時間復(fù)雜度也是O(n)。因此,使用了array_flip之后再使用array_keys的時間復(fù)雜度是O(n)。

接下來,我們看看array_unique函數(shù)的源碼。點擊鏈接查看原始代碼。

/* {{{ proto array array_unique(array input [, int sort_flags])  Removes duplicate values from array */PHP_FUNCTION(array_unique){  // 定義變量  zval *array, *tmp;  Bucket *p;  struct bucketindex {    Bucket *b;    unsigned int i;  };  struct bucketindex *arTmp, *cmpdata, *lastkept;  unsigned int i;  long sort_type = PHP_SORT_STRING;  // 解析參數(shù)  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|l", &array, &sort_type) == FAILURE) {    return;  }  // 設(shè)置比較函數(shù)  php_set_compare_func(sort_type TSRMLS_CC);  // 初始化返回數(shù)組  array_init_size(return_value, zend_hash_num_elements(Z_ARRVAL_P(array)));  // 將值拷貝到新數(shù)組  zend_hash_copy(Z_ARRVAL_P(return_value), Z_ARRVAL_P(array), (copy_ctor_func_t) zval_add_ref, (void *)&tmp, sizeof(zval*));  if (Z_ARRVAL_P(array)->nNumOfElements <= 1) {  /* 什么都不做 */    return;  }  /* 根據(jù)target_hash buckets的指針創(chuàng)建數(shù)組并排序 */  arTmp = (struct bucketindex *) pemalloc((Z_ARRVAL_P(array)->nNumOfElements + 1) * sizeof(struct bucketindex), Z_ARRVAL_P(array)->persistent);  if (!arTmp) {    zval_dtor(return_value);    RETURN_FALSE;  }  for (i = 0, p = Z_ARRVAL_P(array)->pListHead; p; i++, p = p->pListNext) {    arTmp[i].b = p;    arTmp[i].i = i;  }  arTmp[i].b = NULL;  // 排序  zend_qsort((void *) arTmp, i, sizeof(struct bucketindex), php_array_data_compare TSRMLS_CC);  /* 遍歷排序好的數(shù)組,然后刪除重復(fù)的元素 */  lastkept = arTmp;  for (cmpdata = arTmp + 1; cmpdata->b; cmpdata++) {    if (php_array_data_compare(lastkept, cmpdata TSRMLS_CC)) {      lastkept = cmpdata;    } else {      if (lastkept->i > cmpdata->i) {        p = lastkept->b;        lastkept = cmpdata;      } else {        p = cmpdata->b;      }      if (p->nKeyLength == 0) {        zend_hash_index_del(Z_ARRVAL_P(return_value), p->h);      } else {        if (Z_ARRVAL_P(return_value) == &EG(symbol_table)) {          zend_delete_global_variable(p->arKey, p->nKeyLength - 1 TSRMLS_CC);        } else {          zend_hash_quick_del(Z_ARRVAL_P(return_value), p->arKey, p->nKeyLength, p->h);        }      }    }  }  pefree(arTmp, Z_ARRVAL_P(array)->persistent);}/* }}} */

可以看到,這個函數(shù)初始化一個新的數(shù)組,然后將值拷貝到新數(shù)組,然后在45行調(diào)用排序函數(shù)對數(shù)組進行排序,排序的算法是zend引擎的塊樹排序算法。接著遍歷排序好的數(shù)組,刪除重復(fù)的元素。整個函數(shù)開銷最大的地方就在調(diào)用排序函數(shù)上,而快排的時間復(fù)雜度是O(nlogn),因此,該函數(shù)的時間復(fù)雜度是O(nlogn)。

結(jié)論

因為array_unique底層調(diào)用了快排算法,加大了函數(shù)運行的時間開銷,導(dǎo)致整個函數(shù)的運行較慢。這就是為什么array_keys比array_unique函數(shù)更快的原因。



注:相關(guān)教程知識閱讀請移步到PHP教程頻道。
發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
搞黄视频免费在线观看| 亚洲欧美一区二区三区不卡| 4388成人网| 免费在线观看黄| 国产啊啊啊视频在线观看| 精品欧美一区二区三区精品久久| 久久影院在线观看| 884aa四虎影成人精品一区| 国产精品久久久久久久久夜色| 午夜精品小视频| 中文国产成人精品久久一| 亚洲视频一区二区三区| 超碰公开在线| 卡一卡二国产精品| 亚洲精品久久久久久久久久久| 精品网站999www| 日韩免费电影网站| 国产精品www.| 亚洲女同中文字幕| 久久综合九色九九| 欧美日中文字幕| 精品中文视频| 亚洲成av人片在线观看无| 久久日.com| 亚洲国产精品va在线| 欧美国产专区| 欧美videos粗暴高清性| 明星国产一级毛片范冰冰视频| 国产在线观看18| 先锋影音av网站| 欧美成人国产| 欧美日韩美女| 性久久久久久久久久久久| 午夜在线视频| 欧美高清xxxxxkkkkk| 在线播放av更多| 欧美成人一区二区三区在线观看| 欧美激情在线有限公司| 国产精选在线| 国产精品88久久久久久妇女| 久久久精品国产免费观看同学| 国产亚洲人成网站| 麻豆久久久久久久久久| 亚洲在线激情| 亚洲一区二区三区成人在线视频精品| 中文字幕不卡在线视频极品| 国产又爽又黄又嫩又猛又粗| 美女福利视频一区二区| 欧美另类视频在线| 日产精品高清视频免费| av影院在线免费观看| 国产成人亚洲综合| 国产亚洲成av人片在线观看桃| 亚洲日本va在线观看| 精品高清一区二区三区| 精品福利在线观看| 亚洲成a人v欧美综合天堂下载| 国产精品一区二区免费视频| 国产美女激情视频| 日韩在线观看一区| 一区二区欧美在线| 亚洲7777| 能看的毛片网站| 欧美一区二区三区在线免费观看| 欧美一级片免费播放| 欧美激情在线一区| 亚洲女人****多毛耸耸8| 五月天婷亚洲天综合网鲁鲁鲁| 亚洲波多野结衣| 欧美日韩精品在线一区| 污污的视频在线观看| 国产1区2区3区精品美女| 好吊色欧美一区二区三区| 欧美不卡激情三级在线观看| 国产一区二区免费电影| 天天干天天做天天操| 久久久久九九视频| 久久久国产成人| 精品一区二区亚洲| 美女视频网站久久| 成人vr资源| 久久这里有精品| 精品999在线观看| 欧美精品国产白浆久久久久| 日韩a**中文字幕| 91精品国产高清久久久久久91裸体| 91精品婷婷国产综合久久蝌蚪| 成人av网址在线观看| 国产精品久久久久久久久免费| 久久99精品一区二区三区| 大胆av不用播放器在线播放| 亚洲电影中文字幕在线观看| 99re在线精品| aa片在线观看视频在线播放| 宅男一区二区三区| 国产一区二区不卡老阿姨| 蜜桃在线一区二区三区精品| 亚洲人成午夜免电影费观看| www久久99| 国新精品乱码一区二区三区18| 免费在线观看视频一区| 日韩免费大片| 国产精品白丝jk黑袜喷水| 国产黄色的视频| 亚洲欧美中文字幕在线观看| 男人的天堂狠狠干| 午夜精品久久久久久久91蜜桃| 国产亚洲在线播放| 亚洲精品久久7777777| 先锋影音久久久| 欧美极品jizzhd欧美| 99在线小视频| 国产精品久久亚洲| 国产一区观看| 亚洲精品日韩欧美| 高清不卡av| 催眠调教后宫乱淫校园| 最新久久zyz资源站| 五月婷婷丁香综合网| 国产亚洲欧美色| 动漫黄在线观看| 一区二区三区四区乱视频| 97国产精品久久| 国产精品伦理一区二区| 精品人妻午夜一区二区三区四区| 水中色av综合| a级毛片免费观看在线| 91精品国自产在线观看| 希岛爱理一区二区三区av高清| 国产亚av手机在线观看| 97精品在线| 免费看欧美美女黄的网站| 亚洲老头老太hd| 五月婷婷六月综合| 国产又爽又黄网站亚洲视频123| 男男视频亚洲欧美| 成人激情动漫在线观看| 日批视频免费看| 欧美巨大xxxx| 久久久久久久免费视频| 国产精品97在线| 亚洲乱码国产乱码精品精天堂| 国产精品熟妇一区二区三区四区| 亚洲h精品动漫在线观看| 国产精品国产三级国产三级人妇| 国产精品任我爽爆在线播放| 污视频网站在线看| 久久精品国产亚洲高清剧情介绍| 樱花影视一区二区| 国产精品igao网网址不卡| 制服视频三区第一页精品| 日韩在线不卡一区| 欧美精品一卡| 国产日本欧洲亚洲| 久久久久久久9999| 91精品国产一区二区三区动漫| 91精品国产综合久久小美女| 欧美精品久久久| 日本中文字幕影院| 黄网网址免费| 亚洲男人天堂2023| 国产中文在线观看| 欧美成人r级一区二区三区| 日本激情视频在线播放| 国产你懂的在线观看| 亚洲欧美成人在线| 制服师生第一页| 欧美成人高清电影在线| 性8sex亚洲区入口| 中文字幕无码毛片免费看| 欧美日韩综合在线观看| 国产精品一区二区在线观看不卡| 久久精品免费看| 久久激情综合网| 国产精品无码电影| 国产精品久久久久久久成人午夜| 日本中文字幕网址| 亚洲黄色一区| 国产淫片在线观看| 羞羞网站在线| 麻豆网站在线观看| 国产丝袜视频在线观看| 日韩中文视频| 精品国产av一区二区三区| 亚洲精品一区三区三区在线观看| 好吊色一区二区三区| 国产精品**亚洲精品| 国产成人自拍一区| 色一情一乱一乱一区91| 丰满少妇大力进入| 亚洲国产美女视频| 亚洲精品乱码久久久久久蜜桃图片| 久久亚洲精华国产精华液| 成人av在线网址| 懂色av一区二区三区四区五区| 亚洲妇女无套内射精| 久久天天久久| 6699久久国产精品免费| xfplay资源站夜色先锋5566| 欧美日韩在线播放一区二区| 亚洲区精品久久一区二区三区| 日本欧美中文字幕| 噜噜噜久久,亚洲精品国产品| 一色桃子在线| 亚洲一区二区免费在线| 亚洲国产精品久久久男人的天堂| www天堂在线| 性久久久久久久久久久| 97人人澡人人爽| 粉嫩一区二区| 香蕉久久成人网| 一本一道dvd在线观看免费视频| 91视视频在线直接观看在线看网页在线看| 久久久久久国产精品免费播放| 色综合久久精品亚洲国产| 六十路在线观看| 国产精品夜间视频香蕉| 亚洲一区二区三区视频在线播放| 屁屁影院在线观看| 国产一区二区91| 大香煮伊手机一区| 亚洲综合无码一区二区| 日本在线观看不卡| 日韩视频 中文字幕| av亚洲天堂网| 高清一区二区三区av| av中字幕久久| 亚欧无线一线二线三线区别| 丁香六月婷婷| 久久99国产精品久久99小说| 国产精品无码自拍| 777久久久精品一区二区三区| 国产精品无码2021在线观看| 日本韩国在线视频爽| 久久久久久久综合日本| 午夜精品影院在线观看| 精品1区2区在线观看| 外国电影一区二区| 免费短视频成人日韩| 鲁一鲁一鲁一鲁一澡| 精品51国产黑色丝袜高跟鞋| 国产午夜精品视频一区二区三区| 午夜片欧美伦| 亚洲天堂美女视频| 色婷婷色综合| 中文有码在线| 中文字幕欧美日韩一区二区三区| 91麻豆精品国产91久久久更新时间| 97视频在线观看视频免费视频| 大波视频国产精品久久| 亚洲欧美视频一区| 欧美精品乱码久久久久久按摩| 先锋影音av资源在线| 欧洲精品二区| 国产精品一区二区三区在线播放| 91国在线产| 日韩精品在线观看一区| 欧美性xxxx交| 成人一二三区视频| 美女黄色片网站| 国产真人做爰视频免费| 欧美挤奶吃奶水xxxxx| 免费h精品视频在线播放| 欧美日韩一区二区三区四区不卡| 国产美女www爽爽爽视频| 精品久久久久久亚洲精品| 精品蜜桃在线看| 国产精品偷伦视频免费观看国产| 欧美性孕妇孕交| 亚洲综合成人av| 香港日本三级视频| 在线观看精品一区| 天天干在线观看| 又黄又免费的视频| 欧美日韩欧美| 久久出品必属精品| 国产精品jizz视频| 麻豆电影传媒二区| 亚洲欧美日韩一区二区三区在线| 成人精品一区二区三区免费| 久久99精品久久| heyzo高清在线| 欧美激情1区| 国产亚洲欧美一区在线观看| 日本韩国欧美一区二区三区| 欧美综合欧美视频| 日韩伦理片在线观看| 国产综合内射日韩久| 天堂中文在线www| 性高湖久久久久久久久aaaaa| 欧美日韩综合在线免费观看| 国产毛片aaa| 精品免费国产一区二区| 日韩激情一区二区三区| 毛片av一区二区| 亚洲视频狠狠干| 日本一区视频在线观看免费| 国产精品538一区二区在线| 免费在线观看黄色小视频| 久久99久久精品国产| 国产亚洲一区二区三区| 日本.亚洲电影| 91啪九色porn原创视频在线观看| 亚洲片在线资源| 精品在线视频一区二区| 成人动漫在线播放| 免费在线观看a级片| 亚洲丝袜美腿综合| 国产在线拍揄自揄拍无码视频| 精品久久在线观看| 亚洲午夜电影在线观看| 天堂成人在线观看| 北条麻妃国产九九九精品小说| 欧洲av一区二区| 天天操天天干天天爽| 日韩成人在线网站| 疯狂揉花蒂控制高潮h| 亚洲一区在线免费| yw.尤物在线精品视频| 色婷婷激情久久| 国产情侣av自拍| 51一区二区三区| 国产精品毛片久久久久久久av| 成人一区二区三区视频| 欧美激情视频在线免费观看 欧美视频免费一| 亚洲精品国产精品乱码不99| 欧美日韩第一视频| 逼特逼视频在线|