La principale différence entre eux est qu'un closure est une classe et callableun type .
Le callabletype accepte tout ce qui peut être appelé :
var_dump(
is_callable('functionName'),
is_callable([$myClass, 'methodName']),
is_callable(function(){})
);
Lorsqu'un closuresera seulement accepter une fonction anonyme. Notez que dans la version PHP 7.1 , vous pouvez convertir des fonctions à une fermeture comme ceci:
Closure::fromCallable('functionName').
Exemple:
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
}
Alors pourquoi utiliser un closureovercallable ?
Sévérité parce qu'un closureest un objet qui a des méthodes supplémentaires: call(), bind()etbindto() . Ils vous permettent d'utiliser une fonction déclarée en dehors d'une classe et de l'exécuter comme si elle était à l'intérieur d'une 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
Vous n'aimeriez pas appeler des méthodes sur une fonction normale car cela provoquera des erreurs fatales. Donc, pour éviter cela, vous devriez écrire quelque chose comme:
if($cb instanceof \Closure){}
Faire ce contrôle à chaque fois est inutile. Donc, si vous souhaitez utiliser ces méthodes, indiquez que l'argument est unclosure . Sinon, utilisez simplement un fichier normal callback. Par ici; Une erreur est générée lors de l'appel de fonction au lieu de votre code, ce qui facilite grandement le diagnostic.
Sur une note latérale: la closureclasse ne peut pas être étendue comme sa finale .
["Foo", "bar"]pourFoo::barou[$foo, "bar"]pour$foo->bar.