【问题标题】:what happened in PHP8.0.0 to break usort(...(int)(strlen($a)<strlen($b)));?PHP8.0.0 中发生了什么来破坏 usort(...(int)(strlen($a)<strlen($b)));?
【发布时间】:2021-03-30 15:04:43
【问题描述】:

代码

<?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 之前按我的预期打印所有定义的常量,从最长到最短。 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 中发生了什么来破坏这段代码?

【问题讨论】:

    标签: php usort php-8


    【解决方案1】:

    这里的大多数其他答案都集中在如何解决问题上,但我想我会尝试解释为什么这在 PHP 8 中发生了变化,我认为这是你感兴趣的在。

    PHP 8 引入了Stable Sorting RFC,这(听起来)意味着 PHP 中的所有排序函数现在都“稳定”了。链接中有关此的更多详细信息。

    其他答案已经很好地涵盖了这一点,但是您的函数返回零或大于零的数字。以前的 PHP 排序实现(在所有低于 8 的版本中)认为零和负数相同;正如上面的 RFC 所提到的,检查只是针对大于零的数字,或者不是。返回零意味着这些元素的处理方式与$a &lt; $b 的情况相同。

    PHP 引入了弃用警告,因此许多返回布尔值的排序实现仍然可以工作。 RFC 对此提供了更多详细信息,但重要的是,这意味着 PHP 8 仍然向后兼容它们(因此这是弃用通知,而不是警告)。这里的边缘情况是,虽然您的函数有效地返回一个布尔值 - 0 表示相同的长度,而 1 表示 $a &lt; $b 的情况 - 因为您将其转换为整数,但 PHP 8 中的向后兼容性检查不会捕获它,因此所有“相等”的元素都被视为$a &lt; $b

    比较:

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

    在问题中 - 在 PHP 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

    【讨论】:

      【解决方案2】:

      这是因为您返回的是 0 或 1,而不是 -1。 您应该改用 spaceship 运算符: https://3v4l.org/PLYAP

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

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

      【讨论】:

        【解决方案3】:

        我不知道导致这种差异的内部变化是什么,但您的排序回调有点时髦。如果 $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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2022-01-23
          • 1970-01-01
          • 2014-10-19
          • 2010-10-11
          • 2015-02-23
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多