# Closures, rebinding and scopes

- Thread: https://externals.io/message/49200
- Original archive: https://news-web.php.net/php.internals/49200
- Started by Gustavo Lopes on 2010-08-03T18:12:22+00:00
- Messages: 3
- Reply by email to internals@lists.php.net
- More for agents: search with https://externals.io/search.md?q={query} · JSON API at https://externals.io/api · documentation at https://externals.io/llms.txt

---

## #49200 — Gustavo Lopes — 2010-08-03T18:12:22+00:00

URL: https://externals.io/message/49200#49200

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:

1. Change Closure::bind/Closure::bindTo so that they accept a class name  
for static closures and an instance otherwise
2. Provide a method to change simultaneously the (calling) scope and the  
called scope
3. 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

---

## #49206 — Gustavo Lopes — 2010-08-05T13:54:21+00:00

URL: https://externals.io/message/49200#49206 · In reply to: #49200

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

---

## #49207 — Gustavo Lopes — 2010-08-05T14:04:33+00:00

URL: https://externals.io/message/49200#49207 · In reply to: #49206

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
