PHP8.0.0中发生了什么导致usort(...(int)(strlen($a)<strlen($b)))出现问题?

13

代码

<?php
$consts = get_defined_constants();
$consts = array_keys($consts);
usort($consts,function($a,$b){return (int)(strlen($a)<strlen($b));});
foreach($consts as $const){
    echo strlen($const).": ".$const."\n";
}

在 PHP 8.0.0 之前,will 会按照我预期的方式从长到短打印出所有已定义的常量。7.3.13 以此开始。

62: SODIUM_CRYPTO_PWHASH_SCRYPTSALSA208SHA256_MEMLIMIT_INTERACTIVE
62: SODIUM_CRYPTO_PWHASH_SCRYPTSALSA208SHA256_OPSLIMIT_INTERACTIVE
60: SODIUM_CRYPTO_PWHASH_SCRYPTSALSA208SHA256_MEMLIMIT_SENSITIVE
60: SODIUM_CRYPTO_PWHASH_SCRYPTSALSA208SHA256_OPSLIMIT_SENSITIVE
51: SODIUM_CRYPTO_PWHASH_SCRYPTSALSA208SHA256_STRPREFIX

但我不知道 PHP8.0.0 做了什么,输出结果如下:

9: E_WARNING
21: FILTER_FLAG_STRIP_LOW
7: E_ERROR
26: FILTER_FLAG_STRIP_BACKTICK

你可以在3v4l上自行查看: https://3v4l.org/MP2IF

那么PHP 8.0.0中发生了什么导致这段代码失效了呢?

3个回答

18
大多数其他答案都集中在如何解决问题上,但我想尝试解释为什么PHP 8会发生这种变化,我认为这是您感兴趣的。
PHP 8引入了Stable Sorting RFC,这意味着PHP中的所有排序函数现在都是“稳定”的。有关此更多详细信息,请参见链接。
其他答案已经很好地涵盖了这一点,但您的函数返回零或大于零的数字。 PHP中以前的排序实现(在8以下的所有版本中)认为零和负数相同;如上面提到的RFC,检查只是检查是否大于零或不是。返回零将意味着这些元素与$a < $b相同的情况被视为相同。
PHP引入了一个弃用警告,以使许多返回布尔值的排序实现仍然可用。 RFC对此进行了更多的说明,但重要的是它意味着PHP 8仍然向后兼容它们(因此这是一个弃用通知,而不是一个警告)。边缘情况是,虽然您的函数实际上返回一个布尔值-长度相同时为0,$a < $b时为1-因为您将其转换为整数,所以PHP 8中的向后兼容性检查没有捕获它,因此所有“相等”的元素都被认为像$a < $b一样
对比:
function($a, $b) { return (int) (strlen($a) < strlen($b)); }

就像问题所述 - 在PHP <8中可以正常工作,但不会引发弃用通知。https://3v4l.org/MP2IF


function($a, $b) { return strlen($a) < strlen($b); }

返回一个布尔值,以便在 PHP 8 中进行向后兼容性检查。但现在会发出弃用通知。https://3v4l.org/fWR2Y


function($a, $b) { return strlen($b) <=> strlen($a); }

这是一个“正确”的解决方案,在所有版本中都能正常工作(至少从太空船运算符被引入以来)。https://3v4l.org/6XRYW


因为你将它转换为整数,所以 PHP 8 中的向后兼容性检查没有捕捉到它。有趣的是,我将其转换为整数是为了消除我正在更新为 PHP 8 的一些旧的 PHP5-7 代码中的警告 xD。 - undefined

14
因为您返回的是0或1而不是-1。 您应该使用飞船运算符: https://3v4l.org/PLYAP
usort($consts, function($a, $b) {
    return strlen($b) <=> strlen($a);
});

如果两边相等,则应返回0。


5
我不知道内部发生了什么变化导致这种差异,但是你的排序回调函数有点奇怪。它只应该在 $a 和 $b 在功能上“相等”(在这种情况下,如果它们具有相同的字符串长度)时返回 0。否则,如果 $a 应该在 $b 前排序,则应返回 1,否则返回 -1。如果我适当地调整你的回调函数,我会得到预期输出。
usort($consts, function($a, $b) {
    $aLen = strlen($a);
    $bLen = strlen($b);
    if ($aLen === $bLen) {
        return 0;
    }
    return $aLen < $bLen ? 1 : -1;
});

3v4l: https://3v4l.org/UScFO


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接