Główną różnicą między nimi jest to, że closure
jest to klasa i typu .callable
callable
Typ akceptuje wszystko, co można o nazwie :
var_dump(
is_callable('functionName'),
is_callable([$myClass, 'methodName']),
is_callable(function(){})
);
Gdzie closure
będzie tylko zaakceptować anonimową funkcję. Zauważ, że w PHP wersji 7.1 można zamienić funkcje do zamknięcia tak:
Closure::fromCallable('functionName')
.
Przykład:
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
}
Więc po co używać closure
overa callable
?
Surowość, ponieważ closure
jest obiektem, który posiada kilka dodatkowych metod: call()
, bind()
i bindto()
. Pozwalają na użycie funkcji zadeklarowanej poza klasą i wykonanie jej tak, jakby była wewnątrz klasy.
$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
Nie chciałbyś wywoływać metod w normalnej funkcji, ponieważ spowoduje to krytyczne błędy. Aby więc obejść to musiałbyś napisać coś takiego:
if($cb instanceof \Closure){}
Wykonywanie tego sprawdzania za każdym razem jest bezcelowe. Więc jeśli chcesz użyć tych metod, powiedz, że argumentem jest closure
. W przeciwnym razie użyj zwykłego callback
. Tą drogą; Podczas wywołania funkcji zamiast kodu wywoływany jest błąd, co znacznie ułatwia diagnozowanie.
Na marginesie:closure
klasa nie może zostać przedłużony za jego ostateczny .
["Foo", "bar"]
ForFoo::bar
lub[$foo, "bar"]
for$foo->bar
.