La principale differenza tra loro è che a closureè una classe e callableun tipo .
Il callabletipo accetta tutto ciò che può essere chiamato :
var_dump(
is_callable('functionName'),
is_callable([$myClass, 'methodName']),
is_callable(function(){})
);
Quando una closuresarà solo accettare una funzione anonima. Si noti che in PHP versione 7.1 è possibile convertire le funzioni ad una chiusura in questo modo:
Closure::fromCallable('functionName').
Esempio:
namespace foo{
class bar{
private $val = 10;
function myCallable(callable $cb){$cb()}
function myClosure(\Closure $cb){$cb()} // type hint must refer to global namespace
}
function func(){}
$cb = function(){};
$fb = new bar;
$fb->myCallable(function(){});
$fb->myCallable($cb);
$fb->myCallable('func');
$fb->myClosure(function(){});
$fb->myClosure($cb);
$fb->myClosure(\Closure::fromCallable('func'));
$fb->myClosure('func'); # TypeError
}
Quindi perché usare un closureover callable?
Severità perché closureè un oggetto che ha alcuni metodi aggiuntivi: call(), bind()e bindto(). Consentono di utilizzare una funzione dichiarata al di fuori di una classe ed eseguirla come se fosse all'interno di una classe.
$inject = function($i){return $this->val * $i;};
$cb1 = Closure::bind($inject, $fb);
$cb2 = $inject->bindTo($fb);
echo $cb1->call($fb, 2); // 20
echo $cb2(3); // 30
Non si desidera chiamare i metodi su una funzione normale in quanto ciò causerà errori fatali. Quindi, per evitare che dovresti scrivere qualcosa del tipo:
if($cb instanceof \Closure){}
Fare questo controllo ogni volta è inutile. Quindi, se si desidera utilizzare tali metodi, dichiarare che l'argomento è a closure. Altrimenti basta usare un normale callback. Per di qua; Viene generato un errore nella chiamata di funzione anziché nel codice, causando una diagnosi molto più semplice.
Nota a margine: la closureclasse non può essere estesa come finale .
["Foo", "bar"]perFoo::baro[$foo, "bar"]per$foo->bar.