• Czas czytania ~2 min
  • 24.08.2022

Coś, czego nie brałem pod uwagę, to podpowiadanie typów prymitywnych w kontrolerach Laravel. PHP ma tylko cztery skalarne typy prymitywne: bool, int, float i string — dotyczące tras, string i int to najbardziej prawdopodobne typy, których potrzebujesz. Jednak zwykle nie podpowiadam typów skalarnych w moich kontrolerach.

Niedawno pojawił się problem z akcjami kontrolera wskazującymi typ spowodowany przez błąd TypeError, więc chciałbym zademonstrować kilka przykładów, w których można bezpiecznie używać kontrolerów wskazujących typ z int type.

Rozważ następującą akcję dotyczącą trasy i zastanów się, jakiego typu $orderId będzie przy wywołaniu:

$orderId będzie ciągiem, gdy zostanie wywołane to zamknięcie. Jeśli napiszesz szybki test, zobaczysz, że przechodzi on:

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

Teraz załóżmy, że oczekujesz, że identyfikator zamówienia będzie zawsze liczbą całkowitą, więc chcesz podać podpowiedź do parametru:

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

Jeśli wrócisz do testu, zakończy się on niepowodzeniem z następującymi danymi wyjściowymi:

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

Chociaż technicznie przekazujemy ciąg 123do funkcji route, PHP obsługuje to domyślnie za pomocą przymusu typu. Innymi słowy, PHP próbuje przekonwertować naszą wartość z łańcucha na liczbę całkowitą podczas wywoływania funkcji route.

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

Chociaż technicznie to podejście będzie działać i gwarantuje typ < code>liczba całkowita, nadal mamy inny problem, który mogłeś zauważyć: co się stanie, jeśli użytkownik przekaże coś, czego nie można przekonwertować z ciągu na liczbę całkowitą?

Jeśli zaktualizujemy nasz test do następnie otrzymamy błąd TypeError:

Uruchomienie testu spowoduje wyświetlenie następującego błędu:

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

Jeśli chcemy podpowiedzieć liczbę całkowitą w trasie, powinniśmy upewnić się, że nasza trasa ma ograniczenie wyrażenia regularnego:

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

Po dodaniu ograniczenia parametru trasy tylko wartości liczbowe będą pasować do trasa, dzięki czemu wymuszanie typu działa zgodnie z oczekiwaniami. Poniższy test będzie dokładniejszy, aby upewnić się, że nie można dopasować trasy zamówienia do nienumerycznego parametru routera:

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

Teraz możesz założyć, że typ zamykanej trasy bezpiecznie zmienia się na liczbę całkowitą, jeśli chcesz użyć podpowiedzi. Chociaż przypadek użycia jest ograniczony, myślę, że poznanie tego niuansu może pomóc osobom próbującym podpowiedzieć parametry routera.

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

Jak na to wpływają ścisłe typy?< /h2>

Chcę zaznaczyć, że declare(strict_types=1);nie ma żadnego efektu, ponieważ kod wywołujący znajduje się we frameworku Laravel, który nie używa deklaracji strict_types, dlatego wystąpi przymus typu:

W Typ PHP dokumentacja deklaracji, Ścisłe wpisywanie ma następującą uwaga na temat działania ścisłych typów:

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

Ścisłe pisanie dotyczy wywołań funkcji wykonanych z wewnątrz pliku z włączonym ścisłym pisaniem, a nie funkcji zadeklarowanych w tym pliku. Jeśli plik bez włączonego ścisłego wpisywania wywoła funkcję zdefiniowaną w pliku z ścisłym wpisywaniem, preferencja wywołującego (przymusowe wpisywanie) zostanie uszanowana, a wartość zostanie wymuszona.

br>

Alternatywne podejścia

Jeśli masz skalarne parametry routingu w kontrolerach i domknięciach, możesz pominąć typy skalarne i wykonać rzutowanie typu w ramach metody kontrolera:

W większości przypadków będziesz użyj wiązania modelu trasy dla parametrów trasy pasujących do identyfikatorów liczbowych;jednak rozważ to podejście, gdy masz numeryczny parametr trasy, który chcesz podpowiedzieć za pomocą prymitywnego typu skalarnego 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

O

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

O autorze CrazyBoy49z
WORK EXPERIENCE
Kontakt
Ukraine, Lutsk
+380979856297