2

I am trying to understand how far I can go with PHP5's closures/callbacks, but I am currently trapped in a glass case of "why doesn't this work".

In the following example, I understand that the use of $this in a callback (especially when the scope changes) isn't going to work, it's just there to show you how I hope to be able to use callbacks/closures.

class Customer {
  public $name = '';
  public $callback = NULL;

  function __construct($name) {
    $this->name = $name;
  }
  function when_enters($callback) {
    $this->callback = $callback;
  }
  function enter_store() {
    if(is_callable($this->callback))
      call_user_func($this->callback);
  }
}

class Salesman {
  public $customer = NULL;

  function add_customer(&$customer) { 
    $this->customer =& $customer;
    $this->customer->when_enters(function() {
      $this->greet_customer();
    });
  }
  function greet_customer() {
    echo "Hello, {$this->customer->name}!";
  }
}
$salesman = new Salesman();
$customer = new Customer('John');
$salesman->add_customer(&$customer);
$customer->enter_store();

I have been able to reproduce this basic functionally by implementing Salesman as a static class and setting the callback function as Salesman::greet_customer instead of $this->greet_customer().

Basically, what I want to know is... using object instances, is this kind of functionality possible?

2 Answers 2

3

In php, call_user_func can accept a two-element array to call a method on a class. So if you do this:

$this->customer->when_enters(array($this,'greet_customer'));

it will do what you want. Another alternative on PHP 5.3.0 or greater is to use a closure along with a local copy of $this:

$this_copy=$this;
$this->customer->when_enters(function() use ($this_copy) {
    $this_copy->greet_customer();
});
Sign up to request clarification or add additional context in comments.

Comments

1

I have some good news, and some bad news.

The good news is that the next major release of PHP (5.4?) will permit anonymous functions to be properties of a class, and be callable without jumping through hoops, and will allow you to reference $this by binding the function to a specific context.

The bad news is that nobody seems to know when the PHP trunk will be turned into a release.

Now, given that you can't actually reference $this inside the anonymous function, what you can do here is very limited. One option would be to pass the current object to the function:

function enter_store() {
  if(is_callable($this->callback))
    call_user_func($this->callback, $this);
}

While this will work, and allow you to poke at the object from the function, you'd be limited to methods and properties labeled public. This may or may not be an issue for you.

1 Comment

thanks for the link. it really helped alot and I found a ton more to read on the subject. it lead me to this bug report, which was pretty much the exact same workaround @Anomie pointed to. had to give it to them... but thanks again. :)

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.