Note: Sometimes the embedded github gist is not exposed to a guest user. If you have trouble seeing the source code, consider creating an account/logging in to Medium.
If there is one thing I really like about the Laravel PHP Framework, it would be its level of code sophistication, whether it is in something as complex as the ORM or even in something as simple as a helper function. The latter is what this article is about.
Laravel has a Ruby-inspired, higher-order function called
tap(). In a nutshell, the tap helper function takes a value and a callback; passes the value to the callback and returns the value. Let’s take a look at how we could implement such a function from scratch in PHP:
The function takes two arguments:
1. A value,
2. A callback function,
As you can see, inside the function’s body, the
$value is passed as the argument to the callback function and after the invocation of
$value is returned from the
Even though the function looks extremely simple, it opens the door to many possibilities. When I saw this function for the first time, I was like, why would someone even want to use that?!
We’ve all come across this very common 3-step situation:
- We create a new variable by calling a function that returns a value, instantiating a class or any expression that evaluates to some value. e.g.
$foo = bar();,
$foo = new Bar;,
$foo = 40+2;.
- Then we do something with that variable. e.g.
- Eventually, we return that variable.
An example should make more sense:
The tap function allows us to simplify the example in one statement, like this:
Here, we pass an instance of PHP’s built-in, generic
stdClass class as our value and also the callback function which will act upon that value(instance of
stdClass). Inside the callback, we simply assign a string ‘John’ to the
Since the tap function always returns the first argument,
$value, we can immediately access the members of that
new stdClass). So in our case, if we wanted to instantiate a class, set a value to its property and then echo out the value of that property, we could do that all in a single statement:
Again, without the tap function, the above example would take the shape of this:
We can also take this tapping mechanism a bit further. What if we wanted to make the callback function optional? What if all we really want is to call a method of
$value and just get the
$value in return, instead of what the called method actually returns?
$person->setName('John'); // --> returns 'Done'.// For some reason we want to ignore the returned value 'Done':tap($person)->setName('John'); // --> returns $person.// Notice the No. of arguments in tap(). No callback.
setName() is a method of the
$person object. We called the
setName() method but in that process, we also disregarded
setName()'s actual return value (The not-so-useful string
"Done") and returned the
$person instead. Confused? Let’s take a look at a real-world scenario and then we’ll update our implementation of
Say we have a method named
addToWallet() in our
…as you can see if we call the method on
$user object like this:
$user->addToWallet(50); it will, of course, return a
boolean. Let’s say in addition to updating the user’s wallet, we also need to return the
$user from some controller’s action. It would take two statements to achieve that:
But we want something like this one-liner:
return tap($user)->addToWallet($request->amount); // $user
To achieve that we will have to enhance our current implementation of
tap(). Let’s start by making the callback optional first with the default parameter:
Now comes the tricky part. We’ve said that when no callback is passed to the tap (
tap($user)), we would like to return the given value (
$user) from the called method(
->addToWallet(50)) instead of what the called method actually returns.
How can we enforce the method (
addToWallet()) to return the value (
$user), when in its definition, it returns a completely different thing (
true/false) than the value?
PHP has a magic method called
__call() which, if implemented in a class, is invoked “automagically” whenever we try to call a non-existent method on an object of that class. We just have to pass the
$value (which from now on I will also call the
$target) to the constructor of a class that implements
__call(). Let’s call that class
If we create an instance of this
TapWithoutCallback class and try to access a method that doesn’t exist there, it will delegate the method call (line 16) to the target/value that we passed during the instantiation.
As an improvement to our
tap() function, now all we have to do is return an instance of the
TapWithoutCallback class when no callback is passed. The finished version of our tap function looks like this:
Now, if we don’t pass a callback, it will return an instance of
TapWithoutCallback(line 5) instead of returning the original
If we try to call the method
addToWallet() on it:
…which doesn’t exist on the instance that
tap() has returned (
new TapWithoutCallback), PHP will summon its
__call magic method which will call the
addToWallet() on behalf of the target/value (
$user) and then return the
Finally, we can clean up our controller’s action:
Interestingly, we can even chain another method of
User model, since whatever method we call on the model’s instance, is going to return the same instance, regardless of what the method’s actual return value is. So, this is possible:
But now we’ve lost the ability to return the
notify() is no longer being called on the tap’s returned instance. It is now being called directly on
$user. To mitigate this problem, we can stack the tap calls like this (pay close attention to the parentheses):
notify() will now return the tapped value, which is the
$user. Think of the above example as two layers of Inception.
Another use case will be Laravel’s
update() method, which also returns a
boolean. We can leverage the
tap() function to explicitly return the model, instead of the boolean:
Here is the
tap() function that Laravel implements:
HigherOrderTapProxy is our
TapWithoutCallback-equivalent class. Laravel’s
Got any questions? Leave a comment.