Private/protected members are accessible if you set the "newscope" argument (as the manual says).
<?php
$fn = function(){
return ++$this->foo; // increase the value
};
class Bar{
private $foo = 1; // initial value
}
$bar = new Bar();
$fn1 = $fn->bindTo($bar, 'Bar'); // specify class name
$fn2 = $fn->bindTo($bar, $bar); // or object
echo $fn1(); // 2
echo $fn2(); // 3
Closure::bindTo
(PHP 5 >= 5.4.0)
Closure::bindTo — Duplicar el cierre con un objeto vinculado y ámbito de clase nuevos
Descripción
Crea y devuelve una nueva función anónima con el cuerpo y variables vinculadas como ésta, pero posiblemente con un objeto vinculado diferente y un nuevo ámbito de clase.
El "objeto vinculado" determina el valor que $this
tendrá en el cuerpo de la función, y el "ámbito de clase" representa una clase
que determina los miembros privados y protegidos a los que será capaz
de acceder la función anónima. Concretamente, los miembros que serán
visibles son los mismos que si la función anónima fuese un método de
la clase dada como valor del parámetro
newscope.
Los cierres estáticos no pueden tener ningún objeto vinculado (el valor del parámetro
newthis debería ser NULL), pero esta función puede,
no obstante, usarse para cambiar su ámbito de clase.
Esta función se asegurará de que un cierre no estático que tenga una instancia
vinculada se le aplique un ámbito y viceversa. En este punto,
los cierres no estáticos que le son dados un ámbito, excepto una instancia NULL, son hechos
estáticos, y los cierres no estáticos y sin ámbito que le son dados una instancia no
nula se les aplica un ámbito de clase no especificada.
Nota:
Si solamente se quieren duplicar las funciones anónimas, se puede usar cloning en su lugar.
Parámetros
-
newthis -
El objeto al que la función anónima dada debería ser vinculado, o
NULLpara que el cierre sea desvinculado. -
newscope -
El ámbito de clase a la que asociar el cierre, o 'static' para mantener el actual. Si se da un objeto, el tipo del objeto se usará en su lugar. Esto determina la visibilidad de métodos protegidos y privados del objeto vinculado.
Valores devueltos
Devuelve el objeto Closure recién creado
o FALSE en caso de error
Ejemplos
Ejemplo #1 Ejemplo de Closure::bindTo()
<?php
class A {
function __construct($val) {
$this->val = $val;
}
function getClosure() {
//devuelve el cierre vinculado a este objeto y el ámbito
return function() { return $this->val; };
}
}
$ob1 = new A(1);
$ob2 = new A(2);
$cl = $ob1->getClosure();
echo $cl(), "\n";
$cl = $cl->bindTo($ob2);
echo $cl(), "\n";
?>
El resultado del ejemplo sería algo similar a:
1 2
Ver también
- Funciones anónimas
- Closure::bind() - Duplicar un cierre con un objeto vinculado y ámbito de clase especificados
You can do pretty Javascript-like things with objects using closure binding:
<?php
trait DynamicDefinition {
public function __call($name, $args) {
if (is_callable($this->$name)) {
return call_user_func($this->$name, $args);
}
else {
throw new \RuntimeException("Method {$name} does not exist");
}
}
public function __set($name, $value) {
$this->$name = is_callable($value)?
$value->bindTo($this, $this):
$value;
}
}
class Foo {
use DynamicDefinition;
private $privateValue = 'I am private';
}
$foo = new Foo;
$foo->bar = function() {
return $this->privateValue;
};
// prints 'I am private'
print $foo->bar();
?>
Closures can rebind their $this variable, but private/protected methods and functions of $this are not accessible to the closures.
<?php
$fn = function(){
return $this->foo;
};
class Bar{
private $foo = 3;
}
$bar = new Bar();
$fn = $fn->bindTo($bar);
echo $fn(); // Fatal error: Cannot access private property Bar::$foo
With rebindable $this at hand it's possible to do evil stuff:
<?php
class A {
private $a = 12;
private function getA () {
return $this->a;
}
}
class B {
private $b = 34;
private function getB () {
return $this->b;
}
}
$a = new A();
$b = new B();
$c = function () {
if (property_exists($this, "a") && method_exists($this, "getA")) {
$this->a++;
return $this->getA();
}
if (property_exists($this, "b") && method_exists($this, "getB")) {
$this->b++;
return $this->getB();
}
};
$ca = $c->bindTo($a, $a);
$cb = $c->bindTo($b, $b);
echo $ca(), "\n"; // => 13
echo $cb(), "\n"; // => 35
?>
