• Час читання ~3 хв
  • 24.08.2022

Я не врахував примітивних типів підказок типів у контролерах Laravel. PHP має лише чотири скалярні примітивні типи: bool, int, float і string — щодо маршрутів, string і int — найвірогідніші типи, які вам знадобляться. Однак зазвичай я не використовую скалярні примітивні типи підказок типу в своїх контролерах.

Нещодавно я помітив проблему, пов’язану з діями контролера з підказкою типу, спричинену TypeError, тому я хотів би продемонструвати кілька прикладів, коли можна безпечно використовувати контролери з підказкою типу з int тип.

Розгляньте наступну дію маршруту та подумайте, якого типу буде $orderId під час виклику:

$orderId буде рядком, коли викликається це закриття. Якщо ви напишете швидкий тест, ось що ви побачите:

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,
 )

Хоча технічно цей підхід працюватиме та гарантуватиме тип < code>ціле число, у нас є ще одна проблема, яку ви могли помітити: що, якщо користувач передає щось, що не може перетворити рядок на ціле?

Якщо ми оновимо наш тест до наступне, ми отримаємо 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::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

Строга типізація застосовується до викликів функцій, зроблених з файлу з увімкненою строгою типізацією, а не до функцій, оголошених у цьому файлі. Якщо файл без увімкненої суворої типізації виконує виклик функції, визначеної у файлі зі строгою типізацією, уподобання абонента (примусове введення) буде враховано, а значення буде примусово.

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

Якщо у вас є скалярні параметри маршрутизації в контролерах і замиканнях, ви можете опустити скалярні типи та виконати приведення типів у своєму методі контролера:

Здебільшого ви будете використовуйте зв’язування моделі маршруту для параметрів маршруту, які відповідають числовим ідентифікаторам;однак розгляньте цей підхід, якщо у вас є числовий параметр маршруту, який ви хочете ввести-підказку за допомогою примітивного скалярного типу 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