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 — Duplique la fermeture avec un nouvel objet lié et un nouveau contexte de classe.
Description
Crée et retourne une nouvelle fonction anonyme avec le même corps et les même variables liées que l'originale, mais avec un objet lié qui peut être différent, et un nouveau contexte de classe.
L'objet lié détermine la valeur que $this aura dans le corps de la fonction,
et le contexte de classe représente une classe qui détermine à quels membres privés et protégés
la fonction anonyme aura accès. Autrement dit, les propriétés qui seront visibles seront les
mêmes que si la fonction anonyme était une méthode de la classe passée via le paramètre
newscope.
Les fermetures statiques ne peuvent pas avoir d'objet lié (la valeur du paramètre
newthis devrait être NULL), mais le contexte de classe peut,
lui, être changé.
Cette fonction va vérifier qu'une fermeture non-statique à laquelle on passe
un contexte d'objet deviendra liée à cet objet (et ne sera donc plus non-statique),
et vice-versa. Dans ce but, les fermetures non-statiques auxquelles on passe un
contexte de classe mais NULL comme contexte objet seront rendues statiques, et
inversement.
Note:
Si vous voulez seulement dupliquer la fonction anonyme, vous pouvez utiliser le clonage à la place.
Liste de paramètres
-
newthis -
L'objet auquel lier la fonction anonyme, ou
NULLpour une fermeture statique. -
newscope -
Le contexte de classe à associer à la fermeture, ou 'static' pour conserver le contexte actuel. Si un objet est passé, son type sera utilisé. Ceci determine la visibilité des méthodes protégées et privées de l'objet lié.
Valeurs de retour
Retourne la nouvelle fermeture sous la forme d'un objet Closure,
ou FALSE si une erreur survient
Exemples
Exemple #1 Exemple Closure::bindTo()
<?php
class A {
function __construct($val) {
$this->val = $val;
}
function getClosure() {
//retourne une fermeture liée à cet objet et ce contexte
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";
?>
L'exemple ci-dessus va afficher quelque chose de similaire à :
1 2
Voir aussi
- Fonctions anonymes
- Closure::bind() - Duplique une fermeture avec un nouvel objet lié et un nouveau contexte de classe.
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
?>
