You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PHP 8.2.0与7.4.33中usort()行为差异及兼容方案

问题描述

我有如下关联数组:

$all_works = [
    ["title"=>"A Children’s Story", "year"=>"2024"],
    ["title"=>"Occurred during the Day", "year"=>"2021"],
    ["title"=>"Future and Past", "year"=>"2021"],
    ["title"=>"Future and History", "year"=>"2020"],
    ["title"=>"Open the School, Close the Studio", "year"=>"2023"],
    ["title"=>"To Reconstruct, To Rebuild", "year"=>"2024"],
    ["title"=>"Eyeglasses, a Story", "year"=>"2023"],
    ["title"=>"Nomadic Life", "year"=>"2024"],
    ["title"=>"Chipotle!", "year"=>"2022"],
    ["title"=>"between Art & Technology", "year"=>"2020"],
    ["title"=>"interview Script", "year"=>"2018"],
    ["title"=>"memories and confession", "year"=>"2024"],
    ["title"=>"Guest of Pluto", "year"=>"2022"],
    ["title"=>"A Prologue", "year"=>"2022"],
    ["title"=>"You are in this place", "year"=>"2023"],
    ["title"=>"Happening Now", "year"=>"2024"],
    ["title"=>"Review Catalogue", "year"=>"2022"],
    ["title"=>"A living being of Mars", "year"=>"2021"],
];

需求:按子数组的year数值降序排序,当year相同时,按title的自然字母数字顺序排序。

我编写的代码如下:

usort($all_works, function($work1, $work2) {
    return $work2["year"] <=> $work1["year"];
});
echo "<br><br>";
echo "<pre>";
print_r($all_works);
echo "</pre>";

usort($all_works, function($work3, $work4){
    if($work3["year"] == $work4["year"]){
        return strnatcmp($work3["title"], $work4["title"]);
    }else{
        return 0;
    }
});
echo "<br><br>";
echo "<pre>";
print_r($all_works);
echo "</pre>";

运行现象:PHP 8.2.0中结果完全符合预期;但在PHP 7.4.33中,第二次usort后的结果混乱,不仅title排序失效,year的顺序也被打乱。

需要解答的问题:

  • PHP 8.2.0与7.4.33中的usort()行为是否存在差异?
  • PHP 7.4.33中出现该异常的原因是什么?
  • 如何修改代码使其在PHP 7.4.33中也能达到PHP 8.2.0中的效果?

问题分析与解答

1. PHP版本间usort的行为差异

是的,两者存在关键差异:PHP 7.4及更早版本使用的排序算法不保证稳定排序,而PHP 8.0及以后版本默认启用了稳定排序(底层切换为Timsort算法)。稳定排序会保留相等元素的原有相对位置,不稳定排序则不会。

2. PHP 7.4出现异常的原因

你的代码逻辑是先按year降序排序,再对同year的元素按title排序。但PHP 7.4的usort是不稳定排序,第二次调用时,当两个元素year不同时返回0(表示两者相等),排序算法会随意调整这些元素的相对位置,直接破坏了第一次排序好的year顺序,同时也无法正确完成同year内的title排序——因为不稳定排序会打乱原有分组的结构。

3. 修复方案

不要分两次调用usort,而是在一次排序中同时处理两个排序条件,这样无论PHP版本是否支持稳定排序,都能得到正确结果:

usort($all_works, function($a, $b) {
    // 先按year降序比较
    $yearCompare = $b["year"] <=> $a["year"];
    // 如果year相同,再按title自然排序升序比较
    if ($yearCompare === 0) {
        return strnatcmp($a["title"], $b["title"]);
    }
    return $yearCompare;
});

echo "<br><br>";
echo "<pre>";
print_r($all_works);
echo "</pre>";

代码说明

  • 用太空船运算符<=>先比较year,通过$b["year"] <=> $a["year"]实现降序逻辑。
  • 当year相等时,调用strnatcmp对title进行自然字母数字排序,确保同年份内的标题按预期顺序排列。
  • 一次排序完成所有逻辑,彻底避免了不稳定排序带来的问题,兼容所有PHP版本。

内容的提问来源于stack exchange,提问作者Coding_with_a_Tractor

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.23 13:44:53