3

I'm trying to configure an object at runtime passing a callback function like so:

class myObject{
  protected $property;
  protected $anotherProperty;

  public function configure($callback){
    if(is_callable($callback)){
      $callback();
    }
  }
}

$myObject = new myObject(); //
$myObject->configure(function(){
  $this->property = 'value';
  $this->anotherProperty = 'anotherValue';
});

Of course I get the following error:

Fatal error: Using $this when not in object context

My question is if there is a way to achieve this behavior using $this inside a callback function or maybe get a suggestion for a better pattern.

PS: I prefer to use a callback.

2 Answers 2

7

If you are using (or are willing to upgrade to) PHP 5.4, you can the new bindTo method of Closures. This allows you to "re-bind" a closure to a new scope.

Before calling $callback, you can set its $this to what you want.

if(is_callable($callback)){
    $callback = $callback->bindTo($this, $this);
    $callback();
}

DEMO: http://codepad.viper-7.com/lRWHTn

You can also use bindTo outside of the class.

$func = function(){
  $this->property = 'value';
  $this->anotherProperty = 'anotherValue';
};
$myObject->configure($func->bindTo($myObject, $myObject));

DEMO: http://codepad.viper-7.com/mNgMDz

Sign up to request clarification or add additional context in comments.

3 Comments

+1 That's one additional reason to upgrade PHP to its latest version ;-)
+1 this is a great answer, but unfortunately I have to keep the code compatible with PHP5.3.* (all add the 5.3 tag)
@marcioAlmada: I'll leave this here anyway. :-P
6

Starting with your idea, you could pass $this as a parameter to your callback

But note that your callback (which is not declared inside your class) will not be able to access protected nor private properties/methods -- which means you'll have to set up public methods to access those.


Your class would then look like this :

class myObject {
  protected $property;
  protected $anotherProperty;
  public function configure($callback){
    if(is_callable($callback)){
      // Pass $this as a parameter to the callback
      $callback($this);
    }
  }
  public function setProperty($a) {
    $this->property = $a;
  }
  public function setAnotherProperty($a) {
    $this->anotherProperty = $a;
  }
}

And you'd declared you callback, and use it, like this :

$myObject = new myObject(); //
$myObject->configure(function($obj) {
  // You cannot access protected/private properties or methods
  // => You have to use setters / getters
  $obj->setProperty('value');
  $obj->setAnotherProperty('anotherValue');
});


Calling the following line of code just after :

var_dump($myObject);

Would output this :

object(myObject)[1]
  protected 'property' => string 'value' (length=5)
  protected 'anotherProperty' => string 'anotherValue' (length=12)

Which shows that the callback has been executed, and the properties of your object have indeed been set, as expected.

2 Comments

+1 This is a good step forward. I'm going to wait for a possible better answer for a while, before accept.
can you please describe the work flow of this code? there are some things there that I can't understand...I want to fully understand this...does $this inside $callback($this) gonna be $callback($this, 'func')? thanks!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.