user838531
user838531

Reputation: 488

Laravel closure, what is $query, how is $query passed?

I don't understand this construct:

$posts = Post::where(function($query)
        {
            $query->where('title', 'LIKE', "%search%")
                  ->orWhere('body', 'LIKE', "%search%");
        });

Does the function pass $query to itself? Or does $query represent an object that was instantiated elsewhere in the code?

Upvotes: 2

Views: 1654

Answers (2)

Justin Origin Broadband
Justin Origin Broadband

Reputation: 1530

In PHP, closures are "a callable class to which you've bound your parameters manually" (quoted from http://php.net/manual/en/class.closure.php#117427 ).

Laravel makes extensive use of Closure based classes and calls because the class can be instantiated, used and thrown away without the need for persistence.

Consider further usage (passing "out of scope" variables to Closures):

    // This var would not get passed to the closure as it's "out of scope"
    $outOfScopeVar = [12,13,14];

    $posts = Post::where(function($query) use($outOfScopeVar)
    {
        $query->where('title', 'LIKE', "%search%")
              ->orWhere('body', 'LIKE', "%search%")
              ->whereIn('id', function ($query2) use ($outOfScopeVar) {
                  $query2->select('users_posts.posts_id')
                    ->from('users_posts')
                    ->whereIn('users_posts.users_id',$outOfScopeVar)
                    ->get();
              });
    });

In a query context you can use it to construct very complex, but Object Oriented queries.

Outside of queries, Queues and other Closure based functionality such as the Mail construct use closures to define functionality and scope without having to list the entire methods involved. For example with constructing a message, attaching any files, appending the headers, rendering the view etc are all handled by background methods that interact with the passed closure.

You can see how the Mailer class interacts with a passed closure by browsing the documentation.

https://github.com/laravel/framework/blob/master/src/Illuminate/Mail/Mailer.php#L149

As for QueryBuilder:

https://github.com/laravel/framework/blob/43808e3b54973e9c18de01b7390f7d137fa38762/src/Illuminate/Database/Query/Builder.php

Upvotes: 1

Danny
Danny

Reputation: 454

If you'd go deeper to the Laravel source, you can see, that when you passing a closure to the first argument of where, it will be treated as a new nested query:

if ($column instanceof Closure) {
    return $this->whereNested($column, $boolean);
}

And then, it just call your function using call_user_func with a new instance of Query Builder attached as first parameter (query)

$query = $this->newQuery();

$query->from($this->from);

call_user_func($callback, $query);

Long story short: your $query parameter is a new instance of Query Builder.

Upvotes: 2

Related Questions