• Время чтения ~3 мин
  • 24.08.2022

Что-то, что я не учел, — это примитивные типы с подсказками типов в контроллерах Laravel. PHP имеет только четыре скалярных примитивных типа: bool, int, float и string — что касается маршрутов, string и int — наиболее вероятные типы, которые вам понадобятся. Однако обычно я не использую подсказки для скалярных примитивных типов в своих контроллерах.

Недавно я столкнулся с проблемой, связанной с действиями контроллера с подсказками типа, вызванными ошибкой TypeError, поэтому я хотел бы продемонстрировать несколько примеров, где вы можете безопасно использовать контроллеры с подсказками типа с int type.

Рассмотрите следующее действие маршрута и подумайте, какой тип будет у $orderId при вызове:

$orderId будет string при вызове этого замыкания. Если вы напишете быстрый тест, вы увидите, что он проходит следующее:

Route::get('/order/{order_id}', function ($orderId) {
    return [
        'type' => gettype($orderId),
        'value' => $orderId,
    ];
});

Теперь предположим, что вы ожидаете, что идентификатор заказа всегда будет целым числом, поэтому вы хотите указать параметр:

/**
 * A basic test example.
 *
 * @return void
 */
public function test_example()
{
    $response = $this->get('/order/123');
 
    $response->assertJson([
        'type' => 'string',
        'value' => '123',
    ]);
}

Если вы вернетесь к своему тесту, он теперь завершится ошибкой со следующим выводом:

Route::get('/order/{order_id}', function (int $orderId) {
    return [
        'type' => gettype($orderId),
        'value' => $orderId,
    ];
});

Хотя технически мы передаем строку из 123к функции маршрута, PHP обрабатывает это по умолчанию с помощью приведения типов. Другими словами, PHP пытается преобразовать наше значение из строки в целое число при вызове функции маршрута.

--- Expected
+++ Actual
@@ @@
 array (
-  'type' => 'string',
-  'value' => '123',
+  'type' => 'integer',
+  'value' => 123,
 )

Хотя технически этот подход будет работать и гарантирует тип < код>целое, у нас все еще есть еще одна проблема, которую вы, возможно, заметили: что, если пользователь передаст что-то, что не может преобразовать из строки в целое число?

Если мы обновим наш тест до далее мы получим TypeError:

Запуск теста даст вам следующую ошибку:

public function test_example()
{
    $this->withoutExceptionHandling();
 
    $response = $this->get('/order/ABC-123');
 
    $response->assertJson([
        'type' => 'integer',
        'value' => 123,
    ]);
}

Если мы хотим указать целое число в маршруте, мы должны убедиться, что наш маршрут имеет тег ограничение регулярного выражения:

TypeError: Illuminate\Routing\RouteFileRegistrar::{closure}():
Argument #1 ($orderId) must be of type int, string given, called in .../vendor/laravel/framework/src/Illuminate/Routing/Route.php on line 238

После добавления ограничения параметра маршрута только числовые значения будут соответствовать route, таким образом гарантируя, что приведение типов работает должным образом. Следующий тест будет более точным, чтобы убедиться, что вы не можете сопоставить маршрут заказа с нечисловым параметром маршрутизатора:

Route::get('/order/{order_id}', function (int $orderId) {
    return [
        'type' => gettype($orderId),
        'value' => $orderId,
    ];
})->where('order_id', '[0-9]+');

Теперь вы можете предположить, что тип вашего маршрута закрытия безопасно приводится к целому числу, если вы хотите использовать подсказку типа. Хотя варианты использования ограничены, я думаю, что изучение этого нюанса может помочь людям, пытающимся ввести параметры маршрутизатора с подсказками.

public function test_example()
{
    $response = $this->get('/order/ABC-123');
 
    $response->assertNotFound();
}

Как на это влияют строгие типы?< /h2>

Я хотел бы отметить, что declare(strict_types=1);не имеет никакого эффекта, поскольку вызывающий код находится в среде Laravel, которая не использует объявление strict_types, поэтому произойдет приведение типов:

В Тип PHP документация по декларациям, строгая типизация имеет следующее примечание о том, как работают строгие типы:

  1. Laravel’s Controller::callAction() for controllers
  2. Laravel’s Route::runCallable() for closure-based routes

Строгая типизация применяется к вызовам функций из внутри файла с включенной строгой типизацией, а не к функциям, объявленным в этом файле. Если файл без включенной строгой типизации вызывает функцию, определенную в файле со строгой типизацией, предпочтения вызывающей стороны (принудительная типизация) будут учтены, и значение будет принудительно задано.

br>

Альтернативные подходы

Если у вас есть скалярные параметры маршрутизации в контроллерах и замыканиях, вы можете опустить скалярные типы и выполнить приведение типов в методе вашего контроллера:

В большинстве случаев вы будете используйте привязку модели маршрута для параметров маршрута, соответствующих числовым идентификаторам;однако рассмотрите этот подход, если у вас есть числовой параметр маршрута, который вы хотите ввести с помощью примитивного скалярного типа int.

Route::get(
    '/order/{order_id}',
    function ($orderId, SomeService $someService) {
        // Cast for a method that strictly type-hints an integer
        $result = $someService->someMethod((int) $orderId);
        // ...
    }
);

Comments

No comments yet
Yurij Finiv

Yurij Finiv

Full stack

Про мене

Professional Fullstack Developer with extensive experience in website and desktop application development. Proficient in a wide range of tools and technologies, including Bootstrap, Tailwind, HTML5, CSS3, PUG, JavaScript, Alpine.js, jQuery, PHP, MODX, and Node.js. Skilled in website development using Symfony, MODX, and Laravel. Experience: Contributed to the development and translation of MODX3 i...

Об авторе CrazyBoy49z
WORK EXPERIENCE
Контакты
Ukraine, Lutsk
+380979856297