Closure Binding
Closure binding attaches a closure to an object so the closure runs with that object as its inside self. The bound closure can then read private state of that object through $this.
bindTo lets a closure read private state
The read closure is written outside the Note class and uses $this inside. After bindTo attaches it to a note object, the closure reads the private text of that object.
<?php
class Note {
private $text = "Hidden words";
}
$read = function() {
return $this->text;
};
$note = new Note();
$bound = $read->bindTo($note, Note::class);
echo $bound() . "\n";Closure::bind is the static form
Closure::bind takes the closure, the object, and the class name in one call. The result reads the private label of the box in the same way.
<?php
class Box {
private $label = "Tools";
}
$read = function() {
return $this->label;
};
$box = new Box();
$bound = Closure::bind($read, $box, Box::class);
echo $bound() . "\n";One closure, two bindings
The get closure is bound twice, once to each record. Each bound copy reads the name of its own record, so the two lines differ.
<?php
class Record {
private $name;
public function __construct($name) {
$this->name = $name;
}
}
$get = function() {
return $this->name;
};
$a = new Record("Ana");
$b = new Record("Ben");
$first = $get->bindTo($a, Record::class);
$second = $get->bindTo($b, Record::class);
echo $first() . "\n";
echo $second() . "\n";Example
<?php
class Product {
private $name;
private $price;
public function __construct($name, $price) {
$this->name = $name;
$this->price = $price;
}
}
$format = function() {
return $this->name . " costs " . $this->price;
};
$pen = new Product("Pen", 5);
$book = new Product("Book", 12);
$penLine = $format->bindTo($pen, Product::class);
$bookLine = $format->bindTo($book, Product::class);
echo $penLine() . "\n";
echo $bookLine() . "\n";Key points
- bindTo returns a new closure that is attached to the given object.
- The original closure stays unbound, so one closure can serve many objects.
- The second value given to bindTo names the class scope, and that scope is what opens private state.
- Closure::bind does the same job as a static call, with the closure as its first value.
- Inside a bound closure, $this is the object the closure was bound to.
- A binding carries the object, so the same closure bound to two objects reads two different values.
In this example, a formatter closure builds a line from a name and a price through $this. The closure itself holds no product data. Binding it to the pen product makes it read Pen and 5, and binding it to the book product makes it read Book and 12. The two printed lines prove that the binding carries the object.
Note
Binding does not change the class or the object. It only gives the closure an object to run with.
Try it Yourself
Edit the code, then press Run.
Running is simulated
Exercise
What does bindTo hand back?