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.

Charlie Dalsass
  • 123
  • 1
  • 5
  • Just noticed this post, which does explain some of what I'm looking for: https://softwareengineering.stackexchange.com/questions/42193/what-are-the-benefits-of-closure-primarily-for-php?rq=1 – Charlie Dalsass Feb 23 '18 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. – Charlie Dalsass Feb 24 '18 at 15:56
  • The "style" is what everyone expects: https://www.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: http://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 Feb 24 '18 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. – Charlie Dalsass Feb 24 '18 at 16:25

2 Answers2

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.

HorusKol
  • 4,131
  • 1
  • 20
  • 25
  • 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"? – Charlie Dalsass Feb 25 '18 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 Feb 26 '18 at 00: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". – Charlie Dalsass Feb 26 '18 at 00: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.

Charlie Dalsass
  • 123
  • 1
  • 5