admin管理员组

文章数量:1022777

I'm having a hard time understanding how exactly the old version of Laravel's tap function works, more specifically this:

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

        return $value;
    }

I cannot wrap my head around this line $callback($value); We are not saving the result to another variable, why ? Then we are returning the modified value but how is this possible without saving the result of $callback($value); to a variable ?

What I tried is this:

function myTapFunction($value)
{
    tempFn($value);

    return $value;
}

function tempFn($value)
{
    return $value + 5;
}

var_dump( myTapFunction(5) );

but it returns 5, instead of 10. What's the difference between the original function and my implementation?

I'm having a hard time understanding how exactly the old version of Laravel's tap function works, more specifically this:

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

        return $value;
    }

I cannot wrap my head around this line $callback($value); We are not saving the result to another variable, why ? Then we are returning the modified value but how is this possible without saving the result of $callback($value); to a variable ?

What I tried is this:

function myTapFunction($value)
{
    tempFn($value);

    return $value;
}

function tempFn($value)
{
    return $value + 5;
}

var_dump( myTapFunction(5) );

but it returns 5, instead of 10. What's the difference between the original function and my implementation?

Share Improve this question edited Nov 19, 2024 at 13:45 DarkBee 15.5k8 gold badges72 silver badges118 bronze badges asked Nov 19, 2024 at 13:23 IamMeIamMe 111 silver badge2 bronze badges 4
  • to simplify, objects are passed by reference (ie the same object) to methods while simple types (numbers, strings, arrays) are copied over. So your (5) is copied to your method and you modifications are only present on the copy – kris gjika Commented Nov 19, 2024 at 13:37
  • @krisgjika it's not strictly pass-by-reference - as per php/manual/en/language.oop5.references.php - but yes, you're on the right lines. – ADyson Commented Nov 19, 2024 at 13:38
  • 1 medium/@taylorotwell/tap-tap-tap-1fc6fc1f93a6 - Taylor Otwell explains it in this blog post. This feature of tap makes it easy to force any method on an object to return the object itself. basically boils down the use of the function – aynber Commented Nov 19, 2024 at 13:38
  • ...Anyber makes a good point. So a big reason you might use tap() is to do a form of method chaining / fluent interface, without necessarily having to refactor all your classes – ADyson Commented Nov 19, 2024 at 13:40
Add a comment  | 

2 Answers 2

Reset to default 1

I think you are misunderstanding something.

As stated in https://laravel/docs/11.x/helpers#method-tap

The $value will be passed to the closure and then be returned by the tap function. The return value of the closure is irrelevant

It will not return the modified value but the value you passed to it.

Where I think your confusion stems from is the fact that objects are always passed by reference not by value.

So if you have for example $user that is an object and you pass it to a function like:

function capitalizeName($value) {
    $value->name = ucfirst($value->name);
}

$user = (object)['name' => 'john'];
capitalizeName($user);
return $user->name; // will return 'John'

You will change the $user by changing $value.

I think it's designed to be used with instances of an object, rather than simple types.

Example:

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

    return $value;
}


class Test {
    public $val = 0;
    public function increment($val) {
        $this->val += $val;
    }
}

$a = new Test();
var_dump( tap($a, function($value) { return $value->increment(5);}) );

This outputs:

object(Test)#1 (1) {
  ["val"]=>
  int(5)
}

Demo: https://3v4l./gfQt0 .

Your version would work just fine with an object instance too:

function myTapFunction($value)
{
    tempFn($value);

    return $value;
}

function tempFn($value)
{
    return $value->increment(5);
}

class Test {
    public $val = 0;
    public function increment($val) {
        $this->val += $val;
    }
}

$a = new Test();
var_dump( myTapFunction($a) );

Again this outputs:

object(Test)#1 (1) {
  ["val"]=>
  int(5)
}

Live demo: https://3v4l./vMhfc .

So I think you've misunderstood the use case more than anything.

The reason the behaviour is different for object instances is because (unlike simple types) object identifiers sent as a function argument still point to the same object - see the PHP objects and references documentation. Relevant quote reproduced here for ease:

In PHP, an object variable doesn't contain the object itself as value. It only contains an object identifier which allows object accessors to find the actual object. When an object is sent by argument, returned or assigned to another variable, the different variables are not aliases: they hold a copy of the identifier, which points to the same object.

Therefore the $value returned from the tap function will be the variable you passed into it. The difference is, with a simple type such as int, that is unaffected by anything which happens inside the closure, whereas an object modified inside the closure points back to the same original object in memory, thereby causing the object identified in the variable returned by tap() to have been updated as well.

Laravel tap() documentation: https://laravel/docs/11.x/helpers#method-tap

More background / examples regarding tap(): https://medium/@taylorotwell/tap-tap-tap-1fc6fc1f93a6

I'm having a hard time understanding how exactly the old version of Laravel's tap function works, more specifically this:

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

        return $value;
    }

I cannot wrap my head around this line $callback($value); We are not saving the result to another variable, why ? Then we are returning the modified value but how is this possible without saving the result of $callback($value); to a variable ?

What I tried is this:

function myTapFunction($value)
{
    tempFn($value);

    return $value;
}

function tempFn($value)
{
    return $value + 5;
}

var_dump( myTapFunction(5) );

but it returns 5, instead of 10. What's the difference between the original function and my implementation?

I'm having a hard time understanding how exactly the old version of Laravel's tap function works, more specifically this:

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

        return $value;
    }

I cannot wrap my head around this line $callback($value); We are not saving the result to another variable, why ? Then we are returning the modified value but how is this possible without saving the result of $callback($value); to a variable ?

What I tried is this:

function myTapFunction($value)
{
    tempFn($value);

    return $value;
}

function tempFn($value)
{
    return $value + 5;
}

var_dump( myTapFunction(5) );

but it returns 5, instead of 10. What's the difference between the original function and my implementation?

Share Improve this question edited Nov 19, 2024 at 13:45 DarkBee 15.5k8 gold badges72 silver badges118 bronze badges asked Nov 19, 2024 at 13:23 IamMeIamMe 111 silver badge2 bronze badges 4
  • to simplify, objects are passed by reference (ie the same object) to methods while simple types (numbers, strings, arrays) are copied over. So your (5) is copied to your method and you modifications are only present on the copy – kris gjika Commented Nov 19, 2024 at 13:37
  • @krisgjika it's not strictly pass-by-reference - as per php/manual/en/language.oop5.references.php - but yes, you're on the right lines. – ADyson Commented Nov 19, 2024 at 13:38
  • 1 medium/@taylorotwell/tap-tap-tap-1fc6fc1f93a6 - Taylor Otwell explains it in this blog post. This feature of tap makes it easy to force any method on an object to return the object itself. basically boils down the use of the function – aynber Commented Nov 19, 2024 at 13:38
  • ...Anyber makes a good point. So a big reason you might use tap() is to do a form of method chaining / fluent interface, without necessarily having to refactor all your classes – ADyson Commented Nov 19, 2024 at 13:40
Add a comment  | 

2 Answers 2

Reset to default 1

I think you are misunderstanding something.

As stated in https://laravel/docs/11.x/helpers#method-tap

The $value will be passed to the closure and then be returned by the tap function. The return value of the closure is irrelevant

It will not return the modified value but the value you passed to it.

Where I think your confusion stems from is the fact that objects are always passed by reference not by value.

So if you have for example $user that is an object and you pass it to a function like:

function capitalizeName($value) {
    $value->name = ucfirst($value->name);
}

$user = (object)['name' => 'john'];
capitalizeName($user);
return $user->name; // will return 'John'

You will change the $user by changing $value.

I think it's designed to be used with instances of an object, rather than simple types.

Example:

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

    return $value;
}


class Test {
    public $val = 0;
    public function increment($val) {
        $this->val += $val;
    }
}

$a = new Test();
var_dump( tap($a, function($value) { return $value->increment(5);}) );

This outputs:

object(Test)#1 (1) {
  ["val"]=>
  int(5)
}

Demo: https://3v4l./gfQt0 .

Your version would work just fine with an object instance too:

function myTapFunction($value)
{
    tempFn($value);

    return $value;
}

function tempFn($value)
{
    return $value->increment(5);
}

class Test {
    public $val = 0;
    public function increment($val) {
        $this->val += $val;
    }
}

$a = new Test();
var_dump( myTapFunction($a) );

Again this outputs:

object(Test)#1 (1) {
  ["val"]=>
  int(5)
}

Live demo: https://3v4l./vMhfc .

So I think you've misunderstood the use case more than anything.

The reason the behaviour is different for object instances is because (unlike simple types) object identifiers sent as a function argument still point to the same object - see the PHP objects and references documentation. Relevant quote reproduced here for ease:

In PHP, an object variable doesn't contain the object itself as value. It only contains an object identifier which allows object accessors to find the actual object. When an object is sent by argument, returned or assigned to another variable, the different variables are not aliases: they hold a copy of the identifier, which points to the same object.

Therefore the $value returned from the tap function will be the variable you passed into it. The difference is, with a simple type such as int, that is unaffected by anything which happens inside the closure, whereas an object modified inside the closure points back to the same original object in memory, thereby causing the object identified in the variable returned by tap() to have been updated as well.

Laravel tap() documentation: https://laravel/docs/11.x/helpers#method-tap

More background / examples regarding tap(): https://medium/@taylorotwell/tap-tap-tap-1fc6fc1f93a6

本文标签: phpHow exactly does the tap function workStack Overflow