Laravel trans_choice PHP 8.0升级后无法正常工作

Laravel trans_choice not working after PHP 8.0 upgrade

提问人:miken32 提问时间:12/17/2020 更新时间:12/18/2020 访问量:641

问:

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

// 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);

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

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

Locale 不应该出现这种情况,因为我使用的是原始字符串,但为了记录,和 in 都设置为“en”。localelocale_fallbackconfig/app.php

PHP Laravel Laravel 本地化 PHP-8

评论


答:

3赞 miken32 12/18/2020 #1

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

该方法是执行一些正则表达式,然后在条件和值之间进行松散的比较。它在 PHP 7.4 中工作的唯一原因是因为条件 “2” 大致等于 2。在 8.0 中,将字符串与整数进行比较是以更合理的方式完成的,因此该方法在所有情况下都返回 null,并使用单数默认值。

但是,与其使用正则表达式语法,不如这样定义我的字符串:{2,}

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

该函数检测到星号,并将返回短路以给出适当的值。如果我一直在测试除 0、1 或 2 以外的任何值,我的测试在任何版本的 PHP 中都不会通过。

评论

1赞 IMSoP 1/15/2021
我特别喜欢这个答案的最后一句话:一个很好的提醒,要始终检查边界案例代表性的非边界案例。:)