除了sort()函数外,大家平时利用比较多的该数usort()函数了,由于它可以许可你自定义排序规则。
自然而然,对付下面这个场景,须要对每个学生的考试分数从高到低进行排名时,出于惯性,就会很自然连续利用usort()函数。
简短的实当代码是:

<?php// 学生数组$students = array( array(&#39;name' => '张三', 'point' => 76), array('name' => '李四', 'point' => 98), array('name' => '小明', 'point' => 95), array('name' => '小红', 'point' => 83), array('name' => '阿布', 'point' => 88),);// 按分数从高到低排序usort($students, function($left, $right) { if ($left['point'] == $right['point']) { return 0; } return $left['point'] > $right['point'] ? -1 : 1;});// 输出print_r($students);

上面代码运行后,能得到精确的排序结果。
看起来没什么问题,对吧?是的,确实看起来没什么问题。
由于这里只有5个学生。
但是,假设开拓的系统是大型的系统,假设要排序的学生有广东省的全部高考学生,以2017年为例,广东省高考人数大概是75.7万,这时性能又会如何?

php学生类数组PHP高等编程回归原生态数组排序陷阱 Python

让我们大略来做一个仿照的小实验。
用事实结合xhprof性能剖析工具得出的数据来说话。

先轻微加以改装,在进行排序的前后加上xhprof的性能剖析代码。

// 开始xhprof性能剖析xhprof_enable();usort($students, function($left, $right) { if ($left['point'] == $right['point']) { return 0; } return $left['point'] > $right['point'] ? -1 : 1;});// 结束xhprof性能剖析$xhprof_data = xhprof_disable();

关于xhprof的利用,网上已经有很多资料解释,这里不再详细展开。
终极,我们可以看到这样的性能剖析报告:

图4-1 对5个学生利用usort()排序

接下来,我们可以把学生的数量加大一点。
先增加到万的级别,通过指数爆炸很随意马虎做到这一点,以上面5个学生为根本,通过对这5个学生的数据进行11次翻倍后,就可以得到10240组数据。
把下面造数据的代码放在$students变量声明后即可。

// 5 (2 ^ 11) = 10240for ($i = 0; $i < 11; $i ++) { $students = array_merge($students, $students);}

再来看一下,这时期码运行后的性能剖析报告是若何的。

图4-2 对一万多个学生利用usort()排序

我们暂时先不来比拟这些数据,连续完成末了一批排序——仿照近70万学生的成绩排序。
连续把上面循环的次数从原来11次加大到17次,就可以得到655360组数据。
这时,你会创造页面相应已经明显变慢了。
在我测试时,基本利用了13秒。
终极的xhprof性能剖析报告如下:

图4-3 第三组剖析,对65万多个学生利用usort()排序

末了,通过这三组数据,我们来做个汇总和比较,就能明显创造问题所在了。
比拟几个关键的性能指标:实行韶光、内存利用情形和函数调用次数,可以得到以下表格:

表4-3 不同排序函数的性能比较

可以创造,随着学生数量的增加,实行韶光也明显相应变大。
特殊对付函数调用次数,增长的幅度更为明显,并且是绝对值。
即不管是什么配置的做事器,函数调用次数都是不变的。
那么对付第三组,实行了靠近12.9秒,韶光都到哪里去了呢?

学过操作系统的同学都知道,每次函数的调用都存在高下文切换的开销,频繁的函数调用,会产生频繁的堆栈操作。
这也是为什么C/C++措辞会支持内联函数。
再来看一下第三组的调用链就能知道大部分韶光,靠近95.9%都花在了函数的调用上。
剩下的4.1%韶光则花在了自定义函数本身的实行上。

图4-4 第三组的调用链

既然usort()函数存在性能问题,那么该当改用哪个排序函数更得当、更优呢?还记得我们前面学过的array_multisort()函数吗?来看下它的效果若何。
根据前面所学的知识,不难把实现改成:

<?php// 学生数组$students = array( array('name' => '张三', 'point' => 76), array('name' => '李四', 'point' => 98), array('name' => '小明', 'point' => 95), array('name' => '小红', 'point' => 83), array('name' => '阿布', 'point' => 88),);// 制造更多的学生数据// 5 (2 ^ 11) = 10240// 5 (2 ^ 16) = 655360for ($i = 0; $i < 17; $i ++) { $students = array_merge($students, $students);}// 开始xhprof性能剖析xhprof_enable(XHPROF_FLAGS_MEMORY + XHPROF_FLAGS_CPU);//usort($students, function($left, $right) {// if ($left['point'] == $right['point']) {// return 0;// }//// return $left['point'] > $right['point'] ? -1 : 1;//});$points = array();foreach ($students as $it) { $points[] = $it['point'];} array_multisort($points, SORT_DESC, SORT_NUMERIC, $students);// 结束xhprof性能剖析$xhprof_data = xhprof_disable();// print_r($students);$XHPROF_ROOT = realpath(dirname(__FILE__));include_once $XHPROF_ROOT . "/xhprof_lib/utils/xhprof_lib.php";include_once $XHPROF_ROOT . "/xhprof_lib/utils/xhprof_runs.php";// save raw data for this profiler run using default// implementation of iXHProfRuns.$xhprof_runs = new XHProfRuns_Default();// save the run under a namespace "xhprof_foo"$run_id = $xhprof_runs->save_run($xhprof_data, "xhprof_foo");echo "http://localhost/?run=$run_id&source=xhprof_foo\n";

代码改好后,再来看一下xhprof的性能剖析报告。
有没创造,实行韶光已经降为只有约2.7秒了!
比原来的12.9秒,速率上提升了79%!
并且函数调用次数仅有3次!
但也不要愉快太早,由于array_multisort()函数会花费更多的内存。
这正是范例的空间换韶光的做法。
但作为真实的终端用户,他不会关心我们的做事器利用了多少内存,他只关心打开的网站是否顺畅,能不能在更短的韶光内浏览到他感兴趣的商品。
如果弗成,他就会离我们而去。

图4-5 对65万多个学生改用array_multisort()排序

通过上面的数据比拟,以及和改进后的方案比拟,不难总结出,对付同一个函数,不同级别的数据量,其须要的实行韶光是大有不同的。
选择得当的底层函数,对项目、对系统、对用户都是非常有益的。
大略来说,在大型系统开拓中,要慎用usort()函数。
末了,为了方便大家查看,贴一下终极完全的代码。

<?php// 学生数组$students = array( array('name' => '张三', 'point' => 76), array('name' => '李四', 'point' => 98), array('name' => '小明', 'point' => 95), array('name' => '小红', 'point' => 83), array('name' => '阿布', 'point' => 88),);// 制造更多的学生数据// 5 (2 ^ 11) = 10240// 5 (2 ^ 16) = 655360for ($i = 0; $i < 17; $i ++) { $students = array_merge($students, $students);}// 开始xhprof性能剖析xhprof_enable(XHPROF_FLAGS_MEMORY + XHPROF_FLAGS_CPU);//usort($students, function($left, $right) {// if ($left['point'] == $right['point']) {// return 0;// }//// return $left['point'] > $right['point'] ? -1 : 1;//});$points = array();foreach ($students as $it) { $points[] = $it['point'];} array_multisort($points, SORT_DESC, SORT_NUMERIC, $students);// 结束xhprof性能剖析$xhprof_data = xhprof_disable();// print_r($students);$XHPROF_ROOT = realpath(dirname(__FILE__));include_once $XHPROF_ROOT . "/xhprof_lib/utils/xhprof_lib.php";include_once $XHPROF_ROOT . "/xhprof_lib/utils/xhprof_runs.php";// save raw data for this profiler run using default// implementation of iXHProfRuns.$xhprof_runs = new XHProfRuns_Default();// save the run under a namespace "xhprof_foo"$run_id = $xhprof_runs->save_run($xhprof_data, "xhprof_foo");echo "http://localhost/?run=$run_id&source=xhprof_foo\n";

大概还会存在其他的排序陷阱,大家可以在实际项目开拓中,多加留神,平时多总结。
接下来,连续谈论关于数组更多高等的用法。