Laravel Caveat: Implicit binding

Laravel Caveat: Implicit binding

Not sure if this a bug or intended behaviour but there is this little caveat when you use implicit route binding with Laravel . 

Let’s take this example 

Route::get('/test/{a}/{b}', function (\App\User $a, \App\Models\Datasheet $b) {
    dd([
        get_class($a),
        get_class($b)
    ]);
});

The output would be as you would have expected:

array:2 [▼
  0 => "App\User"
  1 => "App\Models\Datasheet"
]

Now if you change the route parameters like this swapping a and b:

Route::get('/test/{b}/{a}', function (\App\User $a, \App\Models\Datasheet $b) {
    dd([
        get_class($a),
        get_class($b)
    ]);
});

You will be met with an error:

Argument 1 passed to Illuminate\Routing\Router::{closure}() must be an instance of App\User, instance of App\Models\Datasheet given

What just happened here?
Seems like the $a and $b were resolved based on their type hints i.e User and Datasheet respectively, but were injected based on the order specified in the route parameter /test/{b}/{a}

Strangely if you change the variable names to be x and y:

Route::get('/test/{b}/{a}', function (\App\User $x, \App\Models\Datasheet $y) {
    dd([
        get_class($x),
        get_class($y)
    ]);
});

You will get

array:2 [▼
  0 => "App\User"
  1 => "App\Models\Datasheet"
]

Now swapping $x and $y would work as expected and “a” and “b” are now just placeholders

Route::get('/test/{b}/{a}', function (\App\User $y, \App\Models\Datasheet $x) {
    dd([
        get_class($x),
        get_class($y)
    ]);
});

Will output

array:2 [▼
  0 => "App\Models\Datasheet"
  1 => "App\User"
]

So just a little thing to keep in mind that when the route parameter names match the callback parameter(variable) names, then the order of the callback parameters matter and the models are resolved using the callback parameter names.

But if the names of route parameters do not match then the models are resolved using the type hint on the callback parameter.

Not a deal breaker for me, but still something I wasn’t expecting.

Leave a Reply

Your email address will not be published. Required fields are marked *