今天来看看经常使用的数组排序函数如 sort, rsort, asort, arsort, ksort, krsort
。话不多说直接找 sort
函数吧。
在 php7.3
源码中搜索 PHP_FUNCTION(sort)
可以搜到如下
其中 .h
文件是C语言的头文件,直接打开 .c
文件。sort
函数如下,其中我加了一点注释。
1 |
|
不但 rsort, asort, arsort, ksort, krsort
这些函数在 array.c
文件中,PHP数组相关的也都在其中。
先说下 rsort, asort, arsort, ksort, krsort
函数内容与 sort
只有细微的差别。ksort、krsort
是根据键排序所以排序规则获取排序函数用的是 php_get_key_compare_func
参数与 php_get_data_compare_func
是一样的。php_get_data_compare_func、php_get_key_compare_func
函数第二个参数意思是是否降序排列,rsort、arsort、krsort
第二个参数都是1。
进行排序时 zend_hash_sort(Z_ARRVAL_P(array), cmp, 1)
第三个参数意思是是否重新排列索引, sort、rsort
传的都是1。
做个表格看下
获取排序函数 | 调用排序 | |
---|---|---|
sort | php_get_data_compare_func(sort_type, 0) | zend_hash_sort(Z_ARRVAL_P(array), cmp, 1) |
rsort | php_get_data_compare_func(sort_type, 1) | zend_hash_sort(Z_ARRVAL_P(array), cmp, 1) |
asort | php_get_data_compare_func(sort_type, 0) | zend_hash_sort(Z_ARRVAL_P(array), cmp, 0) |
arsort | php_get_data_compare_func(sort_type, 1) | zend_hash_sort(Z_ARRVAL_P(array), cmp, 0) |
ksort | php_get_key_compare_func(sort_type, 0) | zend_hash_sort(Z_ARRVAL_P(array), cmp, 0) |
krsort | php_get_key_compare_func(sort_type, 1) | zend_hash_sort(Z_ARRVAL_P(array), cmp, 0) |
其中调用 php_get_data_compare_func
与 php_get_key_compare_func
获取的 cmp
后面再说明。
继续找 zend_hash_sort
,在 zend_hash.h
中。
1 |
|
看来 zend_hash_sort
中调用了 zend_hash_sort_ex
。 zend_hash_sort_ex
在 zend_hash.c
中。
1 |
|
在 zend_sort.c
中找到 zend_sort
,通过备注发现这个排序是源于 LLVM
的 libc++
中的 std::sort
实现的。算是快排的优化版,当元素数小于等于16时有特殊的优化,当元素数小于等于5时直接通过 if else
嵌套判断排序,真是优化的极致。zend_sort_2
、 zend_sort_3
、 zend_sort_4
、 zend_sort_5
中是 if else
嵌套的判断排序就不贴出来了。其中基准点(pivot)计算方式也进行了优化。相比 PHP5
时代的标配快排实现要稳定多了。
1 |
|
最后来说说 cmp
这个函数,当 sort_flags
为 SORT_REGULAR
时 sort
函数的 cmp
调用的是 array.c
中的下面这个函数,返回值分成 小于0(b>1), 0(b==a), 大于0(a>b)对比失败也是0。
1 |
|
再往下追就是 compare_function
很长我就不贴了,简单说下其中先判断 first
和 second
类型,再进行各种分支比较。比较好奇其中的都是字符串时对比方法,追了下发现底层使用的是C的 memcmp
比较这两个串的前N个字节,这个N是这两个串中较小的那个。
最后总结下 PHP7
对比 PHP5
时代数组排序调用逻辑相差不大,但是排序算法优化了很多,更不用说底层的hash table了。
最后的最后文中如有理解错误的点也请指教。