Laravel trans_choice PHP 8.0 升级后无法使用

Laravel trans_choice not working after PHP 8.0 upgrade

我在功能测试中有以下断言:

// just a convenience method to post a CSV file
$this->importData($postdata, $csv)
    ->assertStatus(200)
    ->assertExactJson([
        "alert" => null,
        // response text copied from RoomController::import()
        "message" => sprintf(__("%d items were created or updated."), count($csv_data)),
    ]);

这在 PHP 7.4 中毫无问题地通过了。在不对我的应用程序代码进行任何更改的情况下,我更新到 PHP 8.0,现在显示:

  Failed asserting that two strings are equal.
  --- Expected
  +++ Actual
  @@ @@
  -'{"alert":null,"message":"2 items were created or updated."}'
  +'{"alert":null,"message":"2 item was created or updated."}'

有问题的控制器代码如下所示:

if ($errcount === 0) {
    $response_code = 200;
    $msg = sprintf(
        trans_choice(
            "{0}No items were created or updated.|{1}%d item was created or updated.|{2,}%d items were created or updated.",
            $count
        ),
        $count
    );
} else {
    // some other stuff
}
return response()->json(["message" => $msg, "alert" => $alert], $response_code);

所以我的问题是 trans_choice 出于某种原因返回 PHP 8.0 中的单项。

我无法解释为什么会发生这种情况。回到 PHP 7.4,一切都再次通过,所以它肯定与 PHP 版本相关联。故障排除很困难,因为当我启动 artisan tinker 并执行 echo trans_choice("{0}foo|{1}bar|{2,}baz", 3); 时,无论我使用的是 PHP 7.4 还是 8.0.

,结果总是出现“bar”

Locale 不应包含在内,因为我使用的是原始字符串,但为了记录,config/app.php 中的 localelocale_fallback 都设置为“en”。

好的,经过大量 dumpdd 我能够追踪到 Illuminate\Translation\MessageSelector::extractFromString() 的不同行为,并且还意识到我使用了错误的语法。

该方法在 8.0 中执行一些正则表达式后跟 a loose comparison between the condition and the value. The only reason it worked in PHP 7.4 was because the condition "2," is loosely equal to 2. Comparing strings to integers is done in a more reasonable fashion,因此该方法 return 在所有情况下都是 null,并且使用单数默认值。

但是,我应该这样定义我的字符串,而不是使用正则表达式语法 {2,}

"{0}No items were created or updated.|{1}%d item was created or updated.|{2,*}%d items were created or updated."

星号被函数检测到并短路 return 以给出正确的值。如果我测试的是 0、1 或 2 以外的任何值,我的测试将不会在 PHP.

的任何版本中通过