Solución:
La diferencia es que un Closure
debe ser una función anónima, donde callable
también puede ser una función normal.
Puede ver / probar esto con el ejemplo a continuación y verá que obtendrá un error para el primero:
function callFunc1(Closure $closure) {
$closure();
}
function callFunc2(Callable $callback) {
$callback();
}
function xy() {
echo 'Hello, World!';
}
callFunc1("xy"); // Catchable fatal error: Argument 1 passed to callFunc1() must be an instance of Closure, string given
callFunc2("xy"); // Hello, World!
Entonces, si solo desea escribir una sugerencia, use la función anónima: Closure
y si también desea permitir las funciones normales, use callable
como sugerencia de tipo.
La principal diferencia entre ellos es que un closure
es un clase y callable
a escribe.
los callable
type acepta cualquier cosa que se pueda llamar:
var_dump(
is_callable('functionName'),
is_callable([$myClass, 'methodName']),
is_callable(function(){})
); // all true
Donde un closure
voluntad solamente aceptar una función anónima. Tenga en cuenta que en la versión 7.1 de PHP puede convertir funciones a un cierre como este:
Closure::fromCallable('functionName')
.
Ejemplo:
namespace foo{
class bar{
private $baz = 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 closure
sobre callable
?
Estricidad porque un closure
es un objeto que tiene algunos métodos adicionales: call()
, bind()
y bindto()
. Te permiten usar una función declarada fuera de una clase y ejecutarla como si estuviera dentro de una clase:
$inject = function($i){return $this->baz * $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 métodos en una función normal ya que eso generará errores fatales. Entonces, para eludir eso, tendría que escribir algo como:
if($cb instanceof Closure){}
Hacer esta comprobación cada vez no tiene sentido. Entonces, si desea utilizar esos métodos, indique que el argumento es un closure
. De lo contrario, solo use un callback
. De esta manera; Se genera un error en la llamada a la función en lugar de su código, lo que hace que sea mucho más fácil de diagnosticar.
En otros comentarios: los closure
la clase no se puede extender como su final.