On Aug 10, 2014, at 11:20 AM, Andrea Faulds <a...@ajf.me> wrote:

> Hi!
> 
> Sorry for the slow response, I’ve been on holiday.

No problem!

> On 8 Aug 2014, at 01:32, Josh Watzman <jwatz...@fb.com> wrote:
> 
>> The RFC goes a long way to fixing this, but one important place it misses is 
>> with function references to private and protected methods. The crux of the 
>> issue is that allowing an unbound closure to escape can lead to very 
>> unexpected and unwanted results, as opposed to forcing the closure to be 
>> bound to a particular variable. Consider:
>> 
>> <?php
>> class C {
>> private function priv() { /* ... */ }
>> public function pub() {
>>   // ... do stuff ...
>>   // Return a closure for the caller to call priv at a later date:
>>   return &self::priv;
>> }
>> }
>> 
>> While this example is somewhat contrived, I've certainly wanted to do 
>> something similar before. The intent of this code is for the closure 
>> returned by "pub" to only ever be called on what was $this inside "pub" -- 
>> but not only can you change that with bind() on the closure, "pub" itself 
>> cannot even pre-bind it to the intended $this. Or maybe it technically could 
>> by calling bind() on the result of &self::priv before returning it, but 
>> that's very cumbersome for what is the common case for what you want to do 
>> with "function pointer" to a non-static method.
> 
> Unfortunately, yes, such closures are not pre-bound. However invoking it when 
> it’s unbound will produce the same error as calling any method statically 
> (E_STRICT or E_ERROR), so the issue can be noticed and fixed easily. It’s 
> possible to bind with Closure::bind(&Foo::bar, ‘Foo’); or something like 
> that. I could make it pre-bind, but I’m unwilling to as :: never binds when 
> calling, so it shouldn’t when referencing for consistency.

My point is not that you might forget to bind() the Closure, agree that it's 
taken care of just fine as-is. My point is that there's no way for pub() to 
express that it only ever expects the closure returned to be bound to the 
object on which you called pub(). Not only is the caller free to bind it to 
some other variable, but the bug might not be obvious at all since there's 
nothing constraining the call to bind() to happen nearby to the code in pub() 
where the intent that it only be bound to that object is clear. Everything here 
is conventional, when IMO it should be contractual, most especially since an 
unbound Closure isn't even meaningful to use (except to bind it before using 
it).

>> You can't do any of those things to the "real" function, so it's unclear if 
>> it makes sense to be able to do it to the callable reference.
> 
> Well, closures are immutable, to be fair. bind and bindTo actually produce 
> *new* functions, and they don’t even work on static closures anyway. You’re 
> not really doing these things to the “real” function.

Ah, whoops -- it's apparently an HHVM-ism that you can add properties to 
Closures :) http://3v4l.org/adEgO The rest of the point I was making here 
basically boils down to being able to bind/re-bind them, which is the same as 
the one I'm trying to make above, so I won't belabor it.

Josh Watzman


--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to