Hi
Even though one cannot bind a static closure to an instance, one can
rebind its scope with the Closure::bind/Closure::bindTo:
class foo {
static protected $field = "foo_field";
static function getClosure() {
return static function () {
//causes a crash (fbc already freed) in call after rebinding,
//so let's not use it
//echo get_called_class()
, "\n";
echo static::$field, "\n";
};
}
}
class subFoo {
static protected $field = "subfoo_field";
}
$c = foo::getClosure();
$c(); //foo_field
$c = $c->bindTo(new subFoo());
$c(); //subfoo_field
It doesn't make sense to require an instance in order to change the scope
of a static closure, so perhaps better options would be:
- Change Closure::bind/Closure::bindTo so that they accept a class name
for static closures and an instance otherwise - Provide a method to change simultaneously the (calling) scope and the
called scope - Provide separate methods to change the called scope and the scope
I think either 2 or 3 would be better than 1 because the fact the
rebinding a closure changes its scope is not a great idea. Consider:
class foo {
private $field = "foo";
function getClosure() {
return function () {
echo $this->field, "\n";
};
}
}
class subFoo extends foo {}
$f = new subFoo();
$g = new subFoo();
$c = $f->getClosure();
$c(); //foo
$c = $c->bindTo($g); //or even $c->bindTo($f)
$c(); //fails
Thoughts?
--
Gustavo Lopes
Hi
I've modified Closure::bindTo/Closure::bindTo so that they accept another
argument that defines the new scope. This can either be an object (its
class is used as the scope) or a class name.
I changed the current behavior so that:
- If the scope is not given, the current one is kept. This permits
changing the bound instance without changing the calling scope. The
current behavior (set the scope to the class of the new bound instance)
makes useless rebinding of closures that were defined up in the class
hierarchy. - I also changed the order of the arguments of Closure::bindTo so that I
could unify Closure::bind and Closure::bindTo under a single
implementation which plays nice with zend_parse_method.
Additionally, I added the method Closure::getScope, which returns the
currently set calling scope of the closure.
Finally, I added four tests. Tests closure_038 and closure_039 fail. Both
present memory corruption and, in addition to that, closure_039 also gives
incorrect results because the rebounding confuses the cache. Note that
these problems were already present (they weren't caused by the changes,
as far as I know). I attached the logs.
--
Gustavo Lopes
On Thu, 05 Aug 2010 14:54:21 +0100, Gustavo Lopes glopes@nebm.ist.utl.pt
wrote:
Hi
I've modified Closure::bindTo/Closure::bindTo so that they accept another
argument that defines the new scope. This can either be an object (its
class is used as the scope) or a class name.
[...]
Sending renamed attachments.
--
Gustavo Lopes