2013-12-09 10 views
10

C'è un modo per associare $this a una chiusura passata come parametro? Ho letto e riletto tutto quello che ho trovato in manuale o su Internet, ma nessuno menziona questo comportamento, tranne questo post sul blog: http://www.christophh.net/2011/10/26/closure-object-binding-in-php-54/ che lo menziona ma non mostra come farlo.

Quindi, ecco un esempio. Quando si chiama il metodo get(function() {}), desidero che la funzione di callback passata sia associata all'oggetto associato a $this, ma sfortunatamente non funziona. C'è un modo per farlo?

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 opere. $this è NULL.

risposta

7

In realtà non ho capito perché l'uso del metodo bindTo non ha funzionato in questo caso, ma ho potuto farlo funzionare utilizzando Closure::bind

public function get($callback) { 
    if (!is_callable($callback)) { 
     throw new InvalidArgumentException('Param must be callable.'); 
    } 

    $bound = Closure::bind($callback, $this); 
    $bound(); 
} 

Modifica

Aparently il metodo bindTo ha lo stesso comportamento, così si dovrebbe riassegnare il suo valore di ritorno a $callback. Per esempio:

public function get($callback) { 
    if (!is_callable($callback)) { 
     throw new InvalidArgumentException('Param must be callable.'); 
    } 

    $callback = $callback->bindTo($this); 
    $callback(); 
} 
+1

Dannazione! Grazie mille Guilherme!Ho provato Closure :: bind, ma non sapevo che sarebbe stato il valore di ritorno che avrei dovuto chiamare dopo. –

+0

@ unknown.bird Prego. :) –

+6

E in una riga '$ callback-> bindTo ($ this) -> __ invoke();' :) –

1

Proprio passarlo come argomento:

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); 
}); 

In alternativa, se si ha realmente c'era bisogno di legarlo, si dovrà utilizzare una funzione che ha restituito una funzione, come questo:

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); 
+0

Grazie Benubird (come il tuo nome :)), so già che soluzioni alternative (come ho detto, ho quasi letto tutto quello che ho potuto trovare su questo argomento), ma mi sembra davvero brutto, penso che se un linguaggio implementa chiusure questo dovrebbe essere raggiungibile in modo più diretto. –

2

fare in questo modo:

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); 
}); 
+0

Funziona anche! Quindi è la chiusura di ritorno che è vincolata e non quella originale. –

1

Una piccola correzione: non utilizzare is_callable per verificare se Closure è passato dal parametro.

Perché is_callable accetta anche String con nome della funzione.

public function get(\Closure $callback) { 

    $bound = \Closure::bind($callback, $this); 
    $bound(); 
} 

Con is_callable abbiamo questa possibilità:

$app = new App; 


$app->get('my_function'); 

Se esiste la funzione, questo errore viene generato:

Chiusura :: bind() si aspetta parametro 1 per essere chiusura, string dato

Perché "My_function" è passato in prova di is_callable, ma Closure::bind prevede l'istanza di Closure.

Problemi correlati