Laravel trans_choice не работает после обновления PHP 8.0

В тесте функций у меня есть следующее утверждение:

// 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.

Локаль не должна входить в это, поскольку я использую необработанные строки, но для записи и locale, и locale_fallback в config/app.php установлены в en.


person miken32    schedule 16.12.2020    source источник


Ответы (1)


Хорошо, после большого количества dump и dd я смог отследить различное поведение Illuminate\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.

person miken32    schedule 17.12.2020
comment
Мне особенно нравится последнее предложение этого ответа: хорошее напоминание о необходимости всегда проверять как граничные случаи , так и репрезентативные не граничные случаи. :) - person IMSoP; 15.01.2021