Possible to Call Closure in Context of Object

I’ve searched and searched but it seems like its not possible to reference $this within a closure. I would like to achieve an interface similar to JQuery as shown below. It doesn’t seem like this possible.


User::find()->loop(function() { 
     echo "<p>{$this->username}</p>"; 
});

Is there anyway to make this possible, or is it simply not supported with closures in 5.3? – please advise.

Thanks

You can assign it to a temporary variable.

Yes, I know this can be done:


User::find()->loop(function($user) { 
     echo "<p>{$user->username}</p>"; 
}); 

What I’m asking though is whether its possible to achieve the below:


User::find()->loop(function() { 
     echo "<p>{$this->username}</p>"; 
}); 

Not matter what I attempt, I always seem to get the below error. Which makes total sense considering the nature limitations of closures.

Using $this when not in object context

I’m just wondering if there is any way to possible do it, hacky or otherwise. Perhaps it can be done with Reflection?

This cannot be done using “use” to import parent-scoped this into context. And the use of reflection looks like an overkill to me. Why to? This seems to me artificial and you, probably, should seek another way.

I’m sure you can pass $this in use:


$func = function() use ($this) {
echo $this->username;
}

If not, this should definitely work:


$user = $this;
$func = function() use ($user) {
echo $user->username;
}

You can NOT pass $this in use. You can reference $this as in Tom’s second example above. Be careful, the closure will only have access to the public properties of $this.

Both will not work. $this cannot be passed, and $user does not allow access to private & protected members.

What, you mean like… ehr… foreach and array_map? Don’t mean to trump your thought, TomB, but I don’t see the benefit of this versus “normal” looping. I do see the downsides though.

Such access may not be necessary. If it is necessary it can be granted through direct reference.


class A {
  protected $foo = 0;

  public function bar() {
    $foo &= $this->foo;
    $mar = function() use (&$foo) {
      $foo++;
    }

    echo $this->foo; // 0
    $mar();
    echo $this->foo; // 1
  }
}

This works because the scope chain passes through the method bar. The closure sees $foo as it exists in the scope of bar.

Convoluted? Yes. Necessary? I haven’t ran into a case where it was.

Thanks! Nice solution. Haven’t thought about such a possibility.

$this behaviour in closures is set to change.

http://wiki.php.net/rfc/closures/object-extension

Alright, so it can’t be done, yet - awesome. That pretty much confirms what I already knew. fyi the object reference can’t be brought into the closure scope because it isn’t available. The object being feed into the closure is available within the collection returned via find().

For anyone browsing the thread who hasn’t read the RFC above, or whose eyes glazed over when trying, here’s the current implementation in PHP’s trunk (meaning, download a snapshot now and it will be available but may change at any point). The key part being the Closure::bindTo() method.


<?php

class Example {
    protected $message = 'hello world';
    public function test(Closure $callback) {
        $bound = $callback->bindTo($this);
        $bound();
    }
}
    
$ex = new Example;
$ex->test(function(){
    var_dump($this->message);
});

That is interesting, closures will have access to private and protected members? Wasn’t expecting that, just public. Not sure if I like that a closure can access all class members regardless of being private or protected. In that sense a closure can be used as a virtual extension of an object… kinda neat.

It allows for late blending of methods, and is one way of emulating multiple inheritance in a manner similar to Ruby’s mixin approach. Basically you have a set of methods you’d like an object to have, but don’t necessarily want to tie it to the objects ancestry. One way to handle this is to have closures that you add to a method.