#php #laravel #laravel-localization #php-8
#php #laravel #laravel-локализация #php-8
Вопрос:
У меня есть следующее утверждение в тесте функций:
// 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);
, я всегда получаю «bar» в результате, независимо от того, использую ли я PHP 7.4 или 8.0.
Язык не должен входить в это, поскольку я использую необработанные строки, но для записи оба locale
и locale_fallback
in config/app.php
установлены в «en».
Ответ №1:
Хорошо, после множества dump
и dd
я смог отследить различное поведение IlluminateTranslationMessageSelector::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. Мне особенно нравится последнее предложение этого ответа: хорошее напоминание о том, чтобы всегда проверять как граничные случаи, так и репрезентативные неграничные случаи. 🙂