Hi all,
Since around alpha1, I've been doing some experimenting with closures,
most recently in the form of a filter chain implementation, and I've
discovered that as of beta1 (as was noted in the "removal-of-$this"
RFC) that there is no way to access private or protected members of
any class inside a closure, regardless of where it is defined.
I realize that the question of implicit $this support for closures has
already been discussed and decided upon temporarily (and I certainly
have no wish to rehash it again), however, it seems logical that even
without being bound to an object, closures should still inherit the
scope in which they're defined. Otherwise, this creates a confusing
inconsistency within the language. Consider the following:
class Exposed {
private $_property;
public function __construct($data = null) {
$this->_property = $data;
}
public function getProtected($self, $property) {
return $self->$property;
}
}
$object1 = new Exposed('secret');
$object2 = new Exposed();
// successfully echos "secret"
echo $object2->getProtected($object1, '_property'));
Because of PHP's scope and visibility rules, this works even though
$object1 and $object2 are only associated by common parentage. While
this may have no technical significance, since a closure is actually
it's own class, in practical terms it puts a damper on the usefulness
of the implementation, and is a bit of a "WTF", particularly when
considered in context with "use", which allows closures to inherit and
even modify variables in the declaring scope, regardless of where they
are called.
Again, to clarify, I am not arguing for $this support to be added back
to closures (though if a consensus could be reached before 5.3 final,
that'd be great, too :-)). I am simply suggesting that the current
implementation might be improved and made more consistent (without
designing it into a corner concerning future decisions) by allowing a
closure defined in class X to follow the same rules as any other
method also defined in X.
Any thoughts or feedback would be very much appreciated. :-)
Thanks for your time and consideration,
- Nate Abele
Lead Developer, CakePHP
Hi Nate,
Any thoughts or feedback would be very much appreciated. :-)
The scoping problem is very deeply related to the $this issue: Should
one be able to switch the change of a closure by re-binding it to
another object or not?
It was also an open point in my RFC on object extension in general -
which describes the different approaches to $this and scoping and the
reason why we have do decide BEFORE adding support for that which way we
want it since otherwise we don't be able to change the behaviour later
on if we decide against it.
So, it may be a small WTF that the scope is not inherited at all. But if
we re-add support for that, useful as it may be, there will be no
possibility of changing that in the future - and since the scope is
deeply related to $this, it could be that the then chosen solution for
$this is also incompatible with the scoping version we choose now.
When I reverted OOP support for beta 1, I carefully made sure that the
current implementation in PHP 5.3 is done in such a way that OOP support
may be added later on without dictating which type of OOP support it
will be. Any change to that would limit future choices. And since nobody
here actually continued the OOP <-> Closure discussion for post-5.3
after my revert in beta 1, I don't think that discussion will have
progressed far enough for RC 1 that re-adding scoping behaviour would be
a wise idea.
Regards,
Christian
Just FYI: My stance on the issue hasn't changed, I'm still in favor of
the original behaviour Dmitry and I designed + addition of bindTo () for
dynamic object extension, see:
<http://wiki.php.net/rfc/closures/object-extension
Hello Nate,
Wednesday, March 11, 2009, 9:25:23 PM, you wrote:
Hi all,
Since around alpha1, I've been doing some experimenting with closures,
most recently in the form of a filter chain implementation, and I've
discovered that as of beta1 (as was noted in the "removal-of-$this"
RFC) that there is no way to access private or protected members of
any class inside a closure, regardless of where it is defined.
I realize that the question of implicit $this support for closures has
already been discussed and decided upon temporarily (and I certainly
have no wish to rehash it again), however, it seems logical that even
without being bound to an object, closures should still inherit the
scope in which they're defined. Otherwise, this creates a confusing
inconsistency within the language.
At the moment it simply is impossible to allow $this. Simply becasue we
could not solve resolving it correctly, or figuring out the scope
correctly. An attempt of mine to solve the issues first looked good and
then just brought up more issues and the only way to solve them was to
make everything slower. So we decided to keep closures as external entities
that are not bound to the scope they are created in. In the same way we do
not bind anythign magically. Also it appears that you probably want a real
callback if you ave to access private or protected members. At least from
a pure design stanpoint that is more than obvious. Please leave it for the
moment, we are far to close in PHP 5.3 release process to do somethign
about it now.
Best regards,
Marcus