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
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 ;-)
– Fernando Mertins