在PHP的array_keys和array_unique函数源代码分析

在PHP的array_keys和array_unique函数源代码分析
性能分析

从性能分析看下面的测试代码:
$ =数组();
对于($ = 0;$运行< 10000;$运行+)
$测试= {兰特(0100);

$时间=瞬时(真);

美元= array_unique($试验);

$时间=瞬时(真)至时间;
echo'array独特:美元的时间。;

$时间=瞬时(真);

美元= array_keys(array_flip($试验));

$时间=瞬时(真)至时间;
echo'keys倒装:美元的时间。;

$时间=瞬时(真);

美元= array_flip(array_flip($试验));

$时间=瞬时(真)至时间;
echo'flip倒装:美元的时间。;

结果如下:
正如你可以看到上面的图片,我们需要0.069s使用array_unique功能。使用后array_flip,我们需要0.00152s利用array_keys功能。我们需要0.00146s为两次array_flip功能。

试验结果表明,它是更快的array_flip.so使用后,打电话给array_keys功能比array_unique功能,具体原因是什么让我们看看这两个函数是如何在PHP的底部实现的。

源代码分析
array_keys原数组(阵列/输入/混合,search_value {,} } bool、严格)
只返回从输入数组的键,可选择只为指定的search_value。
php_function(array_keys)
{
变量定义
*输入变量,输入数组 / * * /
* search_value = null值搜索 / * * /
**条目,输入数组中的一个条目。
RES,比较结果
* new_val新价值; / * * /
国际add_key;指示是否应加入关键* * 旗帜
char * string_key字符串键; / * * /
单位string_key_len;
页num_key数字键; / * * /
zend_bool严格= 0; / * * /做严格的比较
hashposition POS;
Int(* is_equal_func(变量),变量,变量* tsrmls_dc)= is_equal_function;

分析过程参数
如果(zend_parse_parameters(zend_num_args(tsrmls_cc),一个| ZB
返回;
}

/ /如果严格是真的,is_equal_func设置is_identical_function,哪个更一致
如果(严格){
is_equal_func = is_identical_function;
}

根据返回的数组/尺寸的search_vale初始化。
如果(search_value!= NULL){
array_init(return_value);
{人}
array_init_size(return_value,zend_hash_num_elements(z_arrval_p(输入)));
}
add_key = 1;

然后输入数组参数,然后返回返回数组。
zend_hash_internal_pointer_reset_ex(z_arrval_p(输入),POS); / /复位指针
通过数组循环
而(zend_hash_get_current_data_ex(z_arrval_p(输入),(void)进入,POS)= =成功){
/ /如果search_value不空
如果(search_value!= NULL){
法官search_value / /和电流值是相同的,并将比较结果保存到add_key变量
is_equal_func(RES,search_value,入口tsrmls_cc);
add_key = zval_is_true(RES);
}

如果(add_key){
/ /创建一个zval结构
make_std_zval(new_val);

根据关键是字符串或整数 / /数字值为return_value
开关(zend_hash_get_current_key_ex(z_arrval_p(输入),string_key,string_key_len,num_key,1,POS)){
案例hash_key_is_string:
zval_stringl(new_val,string_key,string_key_len - 1, 0);
这个函数负责 / /插入值为return_value,如果键已经存在,新值更新相应的值,或直接进入
zend_hash_next_index_insert(z_arrval_p(return_value),new_val,sizeof(zval *),null);
打破;

案例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);
打破;
}
}

移动到下一个
zend_hash_move_forward_ex(z_arrval_p(输入),POS);
}
}
以上是对array_keys底层函数的来源。为了理解方便,我加了一些中文注释。如果你需要看原代码,你可以点击它。这个函数的功能是创建一个临时数组,然后复制到新数组的键-值对。如果在复制过程中出现重复键值,代之以新的价值观。这一功能的主要步骤是zend_hash_next_index_insert函数称为57行和63行,插入元素到数组函数。如果出现重复值,则使用新值更新原始键值的值。否则,将直接插入,时间复杂度为o(n)。
array_flip原数组(阵列/输入)
带键值翻转的返回数组。
php_function(array_flip)
{
定义变量
* * *变量数组,录入,数据;
char * string_key;
单位str_key_len;
num_key页;
hashposition POS;

解析阵列参数
如果(zend_parse_parameters(zend_num_args)(tsrmls_cc,一、阵列)= =失败){
返回;
}

初始化数组
array_init_size(return_value,zend_hash_num_elements(z_arrval_p(数组)));

重置指针
zend_hash_internal_pointer_reset_ex(z_arrval_p(阵列),POS);
每个元素遍历,并执行密钥交换操作
而(zend_hash_get_current_data_ex(z_arrval_p(阵列),(void)进入,POS)= =成功){
初始化一个结构
make_std_zval(数据);
原始数组新数组键的值
开关(zend_hash_get_current_key_ex(z_arrval_p(阵列),string_key,str_key_len,num_key,1,POS)){
案例hash_key_is_string:
zval_stringl(数据,string_key,str_key_len - 1, 0);
打破;
案例hash_key_is_long:
z_type_p(数据)= is_long;
z_lval_p(数据)= num_key;
打破;
}

对新数组值的原始数组分配,如果有重复,则使用新值覆盖旧值。
如果(z_type_pp(进入)= = is_long){
zend_hash_index_update(z_arrval_p(return_value),z_lval_pp(入口),数据,sizeof(数据),null);
否则如果}(z_type_pp(进入)= = is_string){
zend_symtable_update(z_arrval_p(return_value),z_strval_pp(入口),z_strlen_pp(入口)+ 1,数据,sizeof(数据),null);
{人}
zval_ptr_dtor(数据)将自由也zval结构; / * * /
php_error_docref(空tsrmls_cc,e_warning,只能翻转字符串和整数!)
}
zend_hash_move_forward_ex(z_arrval_p(阵列),POS);
}
}
以上是对array_flip函数的来源。点击链接查看原始代码。最主要的功能是做的是创建一个新数组,遍历原数组。排在26,原始数组的值赋给新数组的键。然后,在37行的开头,原始数组的键被分配给新数组的值。如果有重复,新的值来覆盖旧的价值。整个函数的时间复杂度为O(n)的时间复杂度,因此,使用array_keys后array_flip使用O(N)。

接下来,让我们在array_unique功能的源代码看看。点击链接查看原代码。
array_unique原数组(阵列/输入/ int,sort_flags })
从数组中删除重复的值。
php_function(array_unique)
{
定义变量
* * TMP变量数组;
桶*;
结构bucketindex {
桶*;
无符号整型;
};
结构artmp bucketindex *,* * cmpdata,lastkept;
无符号整型;
长sort_type = php_sort_string;

分析参数
如果(zend_parse_parameters(zend_num_args)(tsrmls_cc,阵列,一个| L,sort_type)= =失败){
返回;
}

设置比较函数
php_set_compare_func(sort_type tsrmls_cc);

初始化数组
array_init_size(return_value,zend_hash_num_elements(z_arrval_p(数组)));
将值复制到新数组中。
zend_hash_copy(z_arrval_p(return_value),z_arrval_p(阵列),(copy_ctor_func_t)zval_add_ref,(void *)TMP,sizeof(zval *));

如果(z_arrval_p(阵列)-> nnumofelements <= 1){ / * * /做什么
返回;
}

根据target_hash桶 / *指针和数组创建一个排序
artmp =(结构bucketindex *)pemalloc((z_arrval_p(阵列)-> nnumofelements + 1)* sizeof(struct bucketindex),z_arrval_p(数组));
如果(!artmp){
zval_dtor(return_value);
return_false;
}
为(i = 0,P = z_arrval_p(阵列)-> plisthead;P;i++,P = P - > plistnext){
artmp {我},B = P;
artmp {我}我=我;
}
artmp {我},B = null;
排序
zend_qsort((void *)artmp sizeof(struct,我bucketindex),php_array_data_compare tsrmls_cc);

遍历排序数组,然后删除重复元素。
lastkept = artmp;
对于(cmpdata = artmp + 1;cmpdata -> B;cmpdata ++){
如果(php_array_data_compare(lastkept,cmpdata tsrmls_cc)){
lastkept = cmpdata;
{人}
如果(lastkept ->我> cmpdata ->我){
P = lastkept -> b;
lastkept = cmpdata;
{人}
P = cmpdata -> b;
}
如果(P>nkeylength = = 0){
zend_hash_index_del(z_arrval_p(return_value),P>H);
{人}
如果(z_arrval_p(return_value)=如(symbol_table)){
zend_delete_global_variable(P>P>nkeylength都可以实现,1 tsrmls_cc);
{人}
zend_hash_quick_del(z_arrval_p(return_value),P>P>都可以实现,nkeylength,P>H);
}
}
}
}
Pefree(artmp,z_arrval_p(阵列)->持续);
}
可以看出,该函数初始化一个新数组,然后将该值复制到新数组,然后调用排序函数对45行中的数组进行排序。排序算法是块树排序的Zend引擎算法。然后经过排序的数组,删除重复的元素,整体功能中最昂贵的部分是调用排序功能,以及快速的行的时间复杂度为O(nlogn)。因此,时间功能的复杂度为O(nlogn)。

结论
由于快速调度算法是在array_unique底部调用,函数的时间开销的增加,从而导致整个功能的运行速度慢,这是为什么array_keys比array_unique功能更快。
免责声明:本网信息来自于互联网,目的在于传递更多信息,并不代表本网赞同其观点。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,并请自行核实相关内容。本站不承担此类作品侵权行为的直接责任及连带责任。如若本网有任何内容侵犯您的权益,请及时联系我们,本站将会在24小时内处理完毕。
相关文章
返回顶部