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

Reply via email to