Is there any way to bind $this
to a closure that is passed as a parameter?
I read and reread everything I could find in manual or over the internet, but no one mentions this behaviour, except this blog post:
http://www.christophh.net/2011/10/26/closure-object-binding-in-php-54/
which mentions it but doesn't show how to do it.
So here's an example. When calling the get(function() {})
method I want the callback function that is passed to it was bound to the object i.e. bound to $this
, but unfortunately it doesn't work. Is there any way I can do it?
class APP
{
public $var = 25;
public function __construct() {
}
public function get($callback) {
if (!is_callable($callback)) {
throw new InvalidArgumentException('Paran must be callable.');
}
// $callback->bindTo($this);
$callback->bindTo($this, $this);
$callback();
}
}
$app = new APP();
$app->get(function() use ($app) {
echo '<pre>';
var_dump($app);
echo '<br />';
var_dump($this);
});
$app
works. $this
is NULL.
I actually didn't understand why using the bindTo
method didn't work in this case, but I could get it to work using Closure::bind
public function get($callback) {
if (!is_callable($callback)) {
throw new InvalidArgumentException('Param must be callable.');
}
$bound = Closure::bind($callback, $this);
$bound();
}
Edit
Aparently the bindTo
method has the same behavior, so you should reassign its return value to $callback
. For example:
public function get($callback) {
if (!is_callable($callback)) {
throw new InvalidArgumentException('Param must be callable.');
}
$callback = $callback->bindTo($this);
$callback();
}
Do it like this:
class APP
{
public $var = 25;
public function __construct() {}
public function get($callback) {
if (!is_callable($callback)) {
throw new InvalidArgumentException('Param must be callable.');
}
// $callback->bindTo($this);
// you must save result in another var and call it
$callback1 = $callback->bindTo($this, $this);
$callback1();
}
}
$app = new APP();
$app->get(function() use ($app) {
echo '<pre>';
var_dump($app);
echo '<br />';
var_dump($this);
});
Just pass it as an argument:
public function get($callback) {
if (!is_callable($callback)) {
throw new InvalidArgumentException('Paran must be callable.');
}
// $callback->bindTo($this);
return $callback($this);
}
...
$app = new APP();
$app->get(function($that) use ($app) {
echo '<pre>';
var_dump($app);
echo '<br />';
var_dump($that);
});
Alternatively, if you really did need to bind it, you would have to use a function that returned a function, like this:
public function getCallback($callback) {
return function($app){
return $callback($this, $app);
}
}
...
$app = new APP();
$f = $app->get(function($that, $app) {
echo '<pre>';
var_dump($app);
echo '<br />';
var_dump($that);
});
$f($app);
A small correction: don't use is_callable
to check if Closure
is passed by parameter.
Because is_callable
too accept String with name of function.
public function get(\Closure $callback) {
$bound = \Closure::bind($callback, $this);
$bound();
}
With is_callable
we have this possibility:
$app = new App;
$app->get('my_function');
If function exists, this error is thrown:
Closure::bind() expects parameter 1 to be Closure, string given
Because "My_function" is passed in test of is_callable
, but Closure::bind
expects instance of Closure
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With