Unconventional Laravel: Route groups and `$router`

laravel
Table of Contents

I'd estimate that 99% of Laravel applications register their routes using the Illuminate\Support\Facades\Route class. It looks a little something like:

use Illuminate\Support\Facades\Route;

Route::get('/projects', 'ProjectsController@index');

The official documentation tells you this is the way to register routes and most applications use this method.

A route group is a way of collecting a number of routes and assigning the same properties, or options, to them. For example, you could prefix a group of routes with the same url:

Route::prefix('/projects')->group(function () {
    Route::get('/', 'ProjectsController@index');
    Route::get('/{project}', 'ProjectsController@show');
});

This is a super convenient way of reducing the amount of duplication you would get from individually registering routes with that /projects prefix.

But did you know that you can drop the use of the Route facade inside of the group callback and make use of a $router parameter instead?

The Closure that is passed to the group() method can actually take an argument. I tend to call it $router but you can call it whatever you want. So taking the previous example of a route group, you can do this:

Route::prefix('/projects')->group(function ($router) {
    $router->get('/', 'ProjectsController@index');
    $router->get('/{project}', 'ProjectsController@show');
});

If you wanted to type-hint parameter, you should type hint the Illuminate\Routing\Router class. The line of code responsible can be found here.

To be honest, there aren't really any big pros or cons to this approach. It's more of a "Did you know you could do this?" one.

Some people might think that there is a performance benefit since you're not calling a method on the Route facade each time, but after testing this with 100 routes the difference was literally a couple of milliseconds. This would be down to the fact that, under the hood, Laravel caches the underlying instance so that it doesn't need to be resolved from the container each time.

If you've ever seen or used this approach before, I'd love to know on Twitter.

Thanks for reading 👋

Enjoyed this post or found it useful? Please consider sharing it on Twitter.