Hello. Jelrik, I could easily show a real-world example where using $this in closures could help. Consider Person class which has to verify that email address is unique. Suppose we have validation code in a single place and filter_var_array() is used to check all the data:
class Person { .. function validate() { filter_var_array(array( 'email' => array('filter' => FILTER_CALLBACK, 'callback' => $this->getEmailValidator()) )); } private function getEmailValidator() { return function($email) { // here, $this->id property is used, not only $email argument } } } When $this is available in closures, everything is ok. When you don't have $this - you end up with messy decisions like: private function getEmailValidator() { $self = $this; return function($email) use ($self) { // here, $self->getId() method is used } } .. or: function validate() { filter_var_array(array( // $this->validateEmail() should be public - breaks encapsulation 'email' => array('filter' => FILTER_CALLBACK, 'callback' => array($this, 'validateEmail') )); } Of course, this is a special case - but I could easily imagine ActiveRecord class in which validation is based on a similar approach. This is why $this in closures would be useful for me - however I definitely would like $this not to change ever. 2009/11/19 Jelrik van Hal <jelri...@jelrikvh.nl>: > Victor Bolshov wrote: >> >> Hi. >> >> Personally, I beleive that (A) approach is the best: "bind $this to >> the object scope at creation" and never change it, issue error when >> $this is used where not available. It also seems to me like this way >> it could be implemented with better performance, am I right? >> >> Dynamically changing $this introduces confusion. You can use >> $this->foo or $this->bar() inside a closure, but when $this >> dynamically changes - you cannot be sure that "foo" property or "bar" >> method is still there. Furthermore, dynamic approach introduces even >> more mess when thinking about availability of private/protected class >> members. >> >> Consider this code: >> >> class Foo { >> private $closure; >> function __construct() >> { >> /* It seems natural to me that, doing this assignment from within the >> class, >> one can use private members inside the closure */ >> $this->closure = function() { $this->privateMethod(); }; >> } >> function setClosure($closure) >> { >> $this->closure = $closure; >> } >> function getClosure() >> { >> return $this->closure; >> } >> } >> >> $foo = new Foo(); >> $foo->getClosure()->__invoke();// #CALL-1 >> $foo->setClosure(function() { >> /* >> But is it good to use private members here? It seems like it would >> break encapsulation, >> and the information that the class was designed to hide - is now >> made available in public access, >> although indirect. >> */ >> $this->privateMethod(); >> }); >> $foo->getClosure()->__invoke();// #CALL-2 >> >> In the end, I would like PHP to issue error when $this is used in >> #CALL-2 but to continue working on #CALL-1. >> >> The (A) approach seems to me more predictable, more simple, it has >> less information the developer needs to keep in mind when using >> closures. >> >> 2009/11/17 Mathieu Suen <mathieu.s...@easyflirt.com>: >>> >>> Chris Stockton a écrit : >>>> >>>> Hello, >>>> >>>> On Tue, Nov 17, 2009 at 2:59 AM, Mathieu Suen >>>> <mathieu.s...@easyflirt.com> wrote: >>>>> >>>>> Christian Seiler a écrit : >>>>>> >>>>>> Hi, >>>>>> >>>>>> since a few months have passed since the last discussion on this topic >>>>>> and perhaps people had time to gather some experience with the current >>>>>> closure implementation in PHP 5.3 I'd like to restart the debate on >>>>>> $this in closures and object extension. >>>> >>>> I believe that (D) wins my vote, and it convinces me twice. Once >>>> because I believe it is the most intuitive for users (A), and twice >>>> because I believe it is also the most useful (C) for users. In my >>>> opinion It seems the most "PHP" way. >>>> >>>> -Chris >>>> >>> (D) is quite inconstant: >>> >>> $block = $foo->closur; >>> >>> $foo->closur(); >>> $block(); >>> >>> This would produce 2 different output. >>> For (C) here is my objection: >>> >>> Suppose that we are in a MVC pattern. >>> In a controller on could do: >>> >>> $model->onFailDo(function () {$this->reportError()}); >>> $model->save(); >>> >>> >>> In the model side: >>> >>> public function onFailDo($block) >>> { >>> $this->signalFailure = $block >>> } >>> >>> public function save() >>> { >>> //... Something wrong happen >>> return $this->signalFailure(); >>> } >>> >>> If you dynamically bind the $this you are obliged to treat the error >>> reporting in the model which is not a good idea. Even worst you can't >>> even >>> catch up the error in the controller. >>> It also mean that the closure is getting tightly coupled with anyone who >>> is >>> using it. And passing closure to different object is like spreading >>> dependency over all the system. >>> >>> -- Mathieu Suen >>> >>> -- >>> PHP Internals - PHP Runtime Development Mailing List >>> To unsubscribe, visit: http://www.php.net/unsub.php >>> >>> >> > > Hi, > > Victor, I do wholeheartedly agree with you about the mess things will be > when allowing $this to refer to different things in different contexts of > calling the same closure (B, C and D): I think it'll prove very difficult to > keep track of which call will end up doing exactly what in which > environment. > > What I'm not really aware of are any big advantages of rebinding $this to > the local environment of the calling code: isn't it just making $this/things > unnecessarily difficult? > > Also, I'm wondering why people think there should be a $this inside a > closure. As stated in the RFC/Wiki, closures are not thought out to be used > alongside OO-code. Why would we want to couple them? I see the use of > closures, but not as OO-related tools using $this. What is the problem with > proposal (0), leaving it as it is now? > > -jelrikvh > > -- > PHP Internals - PHP Runtime Development Mailing List > To unsubscribe, visit: http://www.php.net/unsub.php > > -- Regards, Victor -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: http://www.php.net/unsub.php