La principal diferencia entre ellos es que a closurees una clase y callableun tipo .
El callabletipo acepta cualquier cosa que se pueda llamar :
var_dump(
is_callable('functionName'),
is_callable([$myClass, 'methodName']),
is_callable(function(){})
);
Cuando una closurese sólo se aceptará una función anónima. Tenga en cuenta que en PHP versión 7.1 puede convertir funciones a un cierre de este modo:
Closure::fromCallable('functionName').
Ejemplo:
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
}
Entonces, ¿por qué usar un closureover callable?
Rigor porque un closurees un objeto que tiene algunos métodos adicionales: call(), bind()y bindto(). Le permiten usar una función declarada fuera de una clase y ejecutarla como si estuviera dentro de una clase.
$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
No le gustaría llamar a los métodos en una función normal, ya que generará errores fatales. Entonces, para evitar eso, tendrías que escribir algo como:
if($cb instanceof \Closure){}
Hacer esto comprobar cada vez no tiene sentido. Entonces, si desea utilizar esos métodos, indique que el argumento es a closure. De lo contrario, solo use un normal callback. De esta manera; Se genera un error en la llamada de función en lugar de su código, lo que hace que sea mucho más fácil de diagnosticar.
En una nota al margen: La closureclase no se puede extender como su final .
["Foo", "bar"]paraFoo::baro[$foo, "bar"]para$foo->bar.