Aralarındaki temel fark şudur: closure bir sınıf ve callablebir tür olmasıdır .
callableTipi edilebilir bir şey kabul adlandırılan :
var_dump(
is_callable('functionName'),
is_callable([$myClass, 'methodName']),
is_callable(function(){})
);
Nerede bir closureirade yalnızca anonim bir işlevi kabul. PHP sürüm 7.1 size şöyle bir kapatılmasına fonksiyonlarını dönüştürebilirsiniz unutmayın:
Closure::fromCallable('functionName').
Misal:
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
}
Öyleyse neden bir closureüst kullancallable ?
Kısıtlama bir nedeni closurebazı ek yöntemler vardır bir amacıdır: call(), bind()vebindto() . Bir sınıfın dışında bildirilen bir işlevi kullanmanıza ve bir sınıfın içindeymiş gibi çalıştırmanıza izin verir.
$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
Ölümcül hatalara neden olacağından, normal bir işlevde yöntemler çağırmak istemezsiniz. Yani bunu aşmak için şöyle bir şey yazmanız gerekir:
if($cb instanceof \Closure){}
Bu kontrolü her seferinde yapmak anlamsızdır. Dolayısıyla, bu yöntemleri kullanmak istiyorsanız, argümanın birclosure . Aksi takdirde sadece normal kullanın callback. Bu yoldan; Kodunuz yerine işlev çağrısında bir hata ortaya çıkar ve bu da teşhis edilmesini çok daha kolay hale getirir.
Bir yan not:closure sınıf onun kadar uzatılamaz nihai .
["Foo", "bar"]forFoo::barveya[$foo, "bar"]for gibi bir dizi geçirerek çağrılabilir sınıf yöntemlerini de kullanabilirsiniz$foo->bar.