0

Many of Laravel's build-in framework libraries use closures as arguments. What is the primary purpose of this coding style? Is it just to gain more control over the configuration of the function, to use "functional style", or does it provide dependency inversion of some sort?

I'm curious because I wonder whether I should adopt this style for non-framework development.

For example, wouldn't it be easier just to pass in a second string argument, "site.help" to the function Route::get()?

Route::get('help', function () {
   return View::make('site.help');
});

Note: I am not asking about how closures work or what they do, but rather about style.

4
  • Just noticed this post, which does explain some of what I'm looking for: softwareengineering.stackexchange.com/questions/42193/… Commented Feb 23, 2018 at 21:41
  • Maybe I can answer part of this myself. If I were to pass in "site.help" to the function, Route would be dependent on View. This is a dependency which shouldn't be automatically tied to the Route class because they are really two different things, and Route can be more easily tested if it knows nothing about View. Commented Feb 24, 2018 at 15:56
  • The "style" is what everyone expects: php-fig.org/psr/psr-2/#6-closures - The "style" presents things in a common format that alerts the reader to what's going on. The "how they work", that you didn't need to know about, is here: php.net/manual/en/class.closure.php -- There's the pretty look in common format (style) and correctly written code that does what is intended (how to), 2 different things. Ugly spaghetti code might run correctly but it's an eyesore to look at. Beautiful code can be wrong. Two different things. If I knew more about PHP I'd make that an answer.
    – Rob
    Commented Feb 24, 2018 at 16:07
  • Not sure everyone expects that, Rob. Your link to PSR-2 is just a formatting standard you should obey when you do decide to use closures. PSR-2 doesn't address style at the level I'm asking about. Commented Feb 24, 2018 at 16:25

2 Answers 2

2

The Laravel route directives actually do accept a string as the second parameter:

Route::get('/user', 'UserController@index');

This is parsed by the Laravel router to call the desired action in the desired controller, and then inject whatever the action controller returns into the actual response to the user.

However, action controllers can return quite a few different things: views, redirects, strings, json, and so on.

If you were to just put a simple string intended to be a view name, the router will need to know that the string is a view name (and not a controller@action, or a redirect, or a simple string...).

The closure-style callback provides flexibility - and simpler decision making in the parser.

The closure you provide in your question is rather simple - return the named view. It is possible to write some fairly complex responses:

Route::get('posts/{post}/comments/{comment}', function ($postId, $commentId) 
{
     // of course, you'd have to write something to get data from your models and inject into a view
});

Or even, better (thanks to implicit binding):

Route::get('posts/{post}/comments/{comment}', function (App\Post $post, App\Comment $comment) 
{
     return View::make('blog.comment', [
         'comment' => $comment
     ]);
});

In order to achieve the same using strings, you'd need a more complex method footprint for the route directive.

3
  • I guess you are saying the primary reason is "gain more control over the configuration of the function". Good explanation, thanks. Happy to mark as accepted, but do you think "more control" supersedes my answer - "less dependencies"? Commented Feb 25, 2018 at 16:05
  • I think the less dependencies is also a good idea - but I'm not sure that was the primary intention when putting together the router and route configuration to work like it does.
    – HorusKol
    Commented Feb 26, 2018 at 0:30
  • I used the route example because it was the first example I found. There are many.Nevertheless, I'll mark this as accepted answer, since it appears both are valid and perhaps being "primary" is not as important as being "important". Commented Feb 26, 2018 at 0:58
0

The primary reason is so that Route does not have to depend on View. By passing in the function, I am able to reduce dependencies between objects, observe separation of concerns and make each class more testable.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.