为什么 usort 在 7.0 之前的 PHP 上的值相等时还原数组

Why usort reverts an array when values are equals on PHP prior to 7.0

我正在尝试对数组使用 usort,并得到关于 PHP 版本的不同行为:

$arr1 = [
    [
        'points' => 10,
        'date' => 3,
    ],
    [
        'points' => 10,
        'date' => 2,
    ],
    [
        'points' => 10,
        'date' => 1,
    ]
];

usort($arr1, function ($a, $b) {
    if($a['points'] == $b['points']){
      return 0;
    }
    return ($a['points'] < $b['points']) ? 1 : -1;
});

此数组包含一个"date"值,并按此值降序排列,在根据"points"值进行usort后,具有相同"points"值的项目被反转PHP 5.6,并在 PHP 7.0...

上保持原来的顺序

您可以在此处使用不同的 PHP 版本在线测试(请针对 PHP 5.6.29 和 7.0.1 进行测试):http://sandbox.onlinephpfunctions.com/code/2715220539623b4b699ebb3f90a4b01c98eef53d

如何在任何 PHP 版本下获得相同点的相同排序行为?

如果您想在两个版本中获得相同的结果,您将需要确保指定相等项将如何处理其他字段。

所以你可以用...解决这个问题

usort($arr1, function ($a, $b) {
    if($a['points'] == $b['points']){
      return $a['date'] - $b['date'];
    }
    return ($a['points'] < $b['points']) ? 1 : -1;
});

因此,如果 points 值相同,则使用 date 作为微分器(假设数字比较有效。)

    $array = [
        ['points' => 10, 'date' => 3],
        ['points' => 10, 'date' => 2],
        ['points' => 10, 'date' => 1],
    ];

    usort($array, function ($a, $b) {
        if($a['points'] === $b['points']){
            return $b['date'] <=> $a['date'];
        }
        return $a['points'] <=> $b['points'];
    });

    var_dump($array);

正如其他人已经指出的那样,您需要对 多个键进行排序。 PHP 通过其 compare_func 可调用函数提供此功能,并且它还提供了 <=> *("spaceship") 运算符,方便您编写此类函数。

如果您的 compare_func 发现 points 相等,它应该继续比较 date 等等,返回第一个不为零的值。 (您可以使用 or 运算符来执行此操作。)

并且,如果 all 排序键相等,则 usort() 的行为是 "unpredictable." 在这种情况下,您不应该假设记录将以任何特定顺序呈现......甚至从一次调用 usort() 到下一次调用。如果您认为 "this version of PHP 'always' does it this way, and that version 'always' does it some other way," 认为您只是错了。