What are the "bind" and "bindTo" methods of an Closure for?

Asked

Viewed 607 times

6

I was running some tests with anonymous functions in PHP. I already knew that the anonymous functions were an instance of an internal class called Closure.

I ran a test to see if she had any methods, and I realized I had two:

$a = function () {};

var_dump(get_class_methods($a));

Upshot:

array(2) {
  [0]=>
  string(4) "bind"
  [1]=>
  string(6) "bindTo"
}

What are the purposes of these methods bind and bindTo in a Closure?

  • Hello, you can easily check it directly in the official PHP documentation: http://php.net/manual/en/class.closure.php. Scrolling a little soon comes the section Synopsis of the Class where it lists the methods, and just below in the section Index has documentation of each method ;-)

1 answer

2


TL ; DR

  • Doubles the Closure using a new instance for the pseudo-variable $this and a new scope;
  • Parameter $newthis: change the bound object (bound) to pseudo-variable $this of Closure;
  • Parameter $newscope: change the scope of Closure for the pseudo-variable $this and, consequently, the visibility of the methods protected and private;
  • bind is a static and bindTo is an instance.

Explanation

Unfortunately, there is no way to make this a short and direct response, because it involves many cases and situations. However, I will list the two most common and link the others that are "rarest" to find.

Both have the same intention, change the pseudo-variable $this and the scope of a Closure. Only one is static and the other not.

Basically, all Closure created within a class automatically receives the scope of the class. Briefly, it can use the pseudo variable $this and access methods and properties protected or private outside the class in which it was created.

Of manual

As of PHP 5.4.0, when declared in the context of a class, the Current class is Automatically bound to it, making $this available Inside of the Function’s Scope. If this Automatic Binding of the Current class is not Wanted, then Static Anonymous functions may be used Instead.

Then, using the class below:

class Foo
{
    private $number;

    public function __construct($number)
    {
        $this->number = $number;
    }

    public function getClosure()
    {
        return function() {
            echo $this->number;
        };
    }        
}

And running the following code:

$foo = new Foo(10);
$closure = $foo->getClosure();
$closure();

We’ll have the exit:

10

Number 10 is the variable $number class-deprived Foo of the instance $foo.

Using the scope exchange, one can obtain different results by accessing the same variable of another instance, such as:

$foo = new Foo(10);
$foo2 = new Foo(50);
$closureFoo = $foo->getClosure();
$closureFoo();//Primeira execução

echo ' and ';

$closureFoo2 = $closureFoo->bindTo($foo2);
$closureFoo2();//Segunda execução

And the result will be

10 and 50

For the use of bind, the code would be as follows:

$closureFoo2 = Closure::bind($closureFoo , $foo2);

The result 10 refers to the variable $number of the instance $foo. On the other hand, the result 50 refers to the variable $number of the instance $foo2. Changing the scope of Closure, was possible have access the private variable of another instance of the same class.

BindTo and Bind have, respectively, a second and third parameter, called newscope. This parameter should be used when the class type that will be used changes and there is a need to access some variable private or protected.

We will add a new class with exactly the same structure:

class Bar
{
    private $number;

    public function __construct($number)
    {
        $this->number = $number;
    }

    public function getClosure()
    {
        return function() {
            echo $this->number;
        };
    }
}

And with the example below:

$foo = new Foo(10);
$bar = new Bar(50);
$closureFoo = $foo->getClosure();   
$closureBar = $closureFoo->bindTo($bar);
$closureBar();

We will get the following error:

FATAL ERROR Cannot access private Property Bar::$number on line number 15

Note that the classes Foo and Bar have exactly the same structure, except that they are distinct class. Being the visibility of the variable $number class Bar private, it becomes inaccessible to the Closure which has the scope of the class Foo.

It is important to note that the visibility scope of PHP is delimited to the class and not the instance. In this way, an object can have access to methods and variables protected or private of another instance, provided that both are of the same class. As can be seen in the link below: http://php.net/manual/en/language.oop5.visibility.php#language.oop5.visibility-other-Objects

By understanding how the scope resolution between instances of the same class works, it is possible to understand how the scope exchange of different instances, of the same object, does not affect the Closure. However, when the exchange is for a different object, it is not possible to have the same result, even if the structure of the new class is identical to the first.

To have access to the variable, use the parameter newscope

$closureBar = $closureFoo->bindTo($bar , $bar);

And we will get the desired result:

50

Informing that the new scope of Closure is Bar and no more Foo, to Closure will have access to the variables protected and private. The same behavior occurs with methods protected and private.

For information only, the scope does not necessarily need to be an instance, it can also be in the following forms:

$closureBar = $closureFoo->bindTo($bar , 'Bar');//PHP >= 5.4
$closureBar = $closureFoo->bindTo($bar , get_class($bar));//PHP >= 5.4
$closureBar = $closureFoo->bindTo($bar , Bar::class);//PHP 5.5

There are other situations that occur that should be understood, however, the post would be much more extensive than it already is. For this case, I leave two links (both my answers), one about a situation with Reflection

https://stackoverflow.com/questions/40772386/how-can-i-invoke-a-reflectionfunction-wrapping-a-closure-that-utilizes-this/40772588#40772588

and another on how to change the Closure between objects/instances does not change its scope (is in open study group on ZCPE 5.5):

https://groups.google.com/forum/#! msg/rumo-a-certificacao-php/3ZL_f-51nYk/X_1gd-ldEgAJ

Browser other questions tagged

You are not signed in. Login or sign up in order to post.