Der Hauptunterschied zwischen ihnen besteht darin, dass a closureeine Klasse und callableein Typ ist .
Der callableTyp akzeptiert alles, was aufgerufen werden kann :
var_dump(
is_callable('functionName'),
is_callable([$myClass, 'methodName']),
is_callable(function(){})
);
Wo eine closurewird nur eine anonyme Funktion übernehmen. Beachten Sie, dass Sie in PHP Version 7.1 Funktionen wie folgt in einen Abschluss konvertieren können :
Closure::fromCallable('functionName').
Beispiel:
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
}
Warum also ein closureOver verwenden callable?
Strikt weil eine closureist ein Objekt , das einige zusätzliche Methoden hat: call(), bind()und bindto(). Mit ihnen können Sie eine außerhalb einer Klasse deklarierte Funktion verwenden und so ausführen, als ob sie sich innerhalb einer Klasse befindet.
$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
Sie möchten keine Methoden für eine normale Funktion aufrufen, da dies schwerwiegende Fehler verursacht. Um dies zu umgehen, müsste man so etwas schreiben wie:
if($cb instanceof \Closure){}
Dies jedes Mal zu überprüfen ist sinnlos. Wenn Sie diese Methoden verwenden möchten, geben Sie an, dass das Argument a ist closure. Ansonsten einfach einen normalen verwenden callback. Diesen Weg; Beim Funktionsaufruf wird anstelle Ihres Codes ein Fehler ausgegeben, der die Diagnose erheblich erleichtert.
Nebenbei bemerkt: Die closureKlasse kann nicht als endgültig erweitert werden .
["Foo", "bar"]fürFoo::baroder[$foo, "bar"]für$foo->bar.