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?
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();
});
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.
精彩评论