Tap in Laravel

11,710

In this tutorial, we will talk about tap in Laravel. We will discuss tap helper function and tap method on collections in detail.

Tap Helper Function

Old implementation

Laravel comes up with a tap function. It is a pretty odd function, inspired by Ruby. Here is the basic implementation of Tap helper function.

function tap($value, $callback)
{
    $callback($value);

    return $value;
}

The above code will accept an argument and it will call an anonymous function with that argument. After calling the callback function, it will return the argument.
Let’s see how we can use it in a meaningful way. For instance:

<?php

return tap($photo, function($photo) {
    $photo->validated = true;
    $photo->save();
});

In the above example, we pass a single argument (Photo Model) and a callback function that simply sets validated to true and save the model. This function will then return the Photo Model instance back to the caller.

New implementation

In the latest versions of Laravel 5.4 and in Laravel 5.5, Higher Order Tap came in. It introduced the ability to shorten tap calls. Here is the new implementation of Tap function.

function tap($value, $callback = null)
{
    if (is_null($callback)) {
        return new HigherOrderTapProxy($value);
    }

    $callback($value);

    return $value;
}

Callback function is now optional. You could also chain multiple methods of the argument passed. For example

<?php

$photo = App\Photo::find(1);
return tap($photo)->update([
    'validated' => 'true',
])

We are able to chain any of the Model’s method on tap call. Update method normally returns true or false, but we have used the tap function here. In this case, it will return Photo model we tapped in. Tap makes it helpful to return the Object passed as an argument.

How it works?

Tap is a very helpful function, but sometimes its quite confusing to think how it works. Let me explain to you how it actually works.
If the callback function is not given as it is optional, Laravel will return a new instance of HigherOrderTapProxy. There is call magic method defined in the HigherOrderTapProxy class. Call magic method is called dynamically by the language if the
called method is not defined in the class. Since, there are no methods defined in the HigherOrderTapProxy class except call magic method, it will call it every time you chain any method calls with tap function. In the call magic method, our update method or any method that we called, will be called with the parameters and it will return the argument that we passed orginally to the tap function.
Here are the actual contents of the call magic method in HigherOrderTapProxy class.

public function __call($method, $parameters)
{
    $this->target->{$method}(...$parameters);

    return $this->target;
}

In the above code, target property is the argument that we passed inside the tap.

Laravel Collection Tap Method

Laravel also includes a tap method on collections that allows you to tap into a collection at a specific point and do something with those results. Tap does not affect the results of the main collection. It is beneficial in debugging your code and finding where things get wrong while working with collections.
Let’s use an example to explain this method. You have the following array.

$photos = [
    ['file_name' => 'wallpaper', 'validated' => true, 'extension' => 'jpg'],
    ['file_name' => 'spring', 'validated' => true, 'extension' => 'png'],
    ['file_name' => 'flowers', 'validated' => false, 'extension' => 'jpg'],
    ['file_name' => 'mac', 'validated' => true, 'extension' => 'png'],
    ['file_name' => 'books', 'validated' => false, 'extension' => 'jpg'],
    ['file_name' => 'mobiles', 'validated' => false, 'extension' => 'jpg'],
    ['file_name' => 'glass', 'validated' => false, 'extension' => 'png'],
    ['file_name' => 'fruit', 'validated' => true, 'extension' => 'jpg'],
];

Now let’s try to use the tap method on this array. First, we have to convert this array into a collection and then tap the collection at a specific point.

return collect($photos)
    ->where('validated', true)
    ->tap(function ($validated) {
        return var_dump($validated->pluck('file_name'));
    });
});

Above code will output the following for the first tap:

wallpaper
spring
mac
fruit

Tap versus Pipe

In Laravel, there is also a similar method to tap named pipe. They are similar in a sense because both of them are used inside a collection pipeline. There is one difference between tap and pipe. Tap allows you to work with data but it does not modify the original return value. On the other hand, pipe modifies the data based on its return value.
For instance:

return collect($photos)
    ->where('validated', true)
    ->pipe(function ($validated) {
        return $validated->where('extension', 'jpg')->pluck('file_name');
    });
});

Above code will output the following based on the $photos array.

wallpaper
fruit

On the other hand if we used the above code with tap like this:

return collect($photos)
    ->where('validated', true)
    ->tap(function ($validated) {
        return $validated->where('extension', 'jpg')->pluck('file_name');
    });
});

It will return the all of the photos array where validated is set to true.

0: {
file_name: "wallpaper",
validated: true,
extension: "jpg"
},
1: {
file_name: "spring",
validated: true,
extension: "png"
},
3: {
file_name: "mac",
validated: true,
extension: "png"
},
7: {
file_name: "fruit",
validated: true,
extension: "jpg"
}

Leave your comments and queries below. I will respond to them as fast as I can.

You might also like
Comments