Sự khác biệt chính giữa chúng closure
là một lớp và callable
một loại .
Các callable
loại chấp nhận bất cứ điều gì có thể được gọi là :
var_dump(
is_callable('functionName'),
is_callable([$myClass, 'methodName']),
is_callable(function(){})
);
Trường hợp closure
sẽ chỉ chấp nhận một chức năng ẩn danh. Lưu ý rằng trong phiên bản PHP 7.1, bạn có thể chuyển đổi các hàm thành một bao đóng như vậy :
Closure::fromCallable('functionName')
.
Thí dụ:
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
}
Vậy tại sao nên sử dụng một closure
hơncallable
?
Nghiêm khắc vì một closure
là một đối tượng mà có một số phương pháp bổ sung: call()
, bind()
và bindto()
. Chúng cho phép bạn sử dụng một hàm được khai báo bên ngoài một lớp và thực thi nó như thể nó nằm trong một lớp.
$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
Bạn không muốn gọi các phương thức trên một hàm bình thường vì điều đó sẽ gây ra các lỗi nghiêm trọng. Vì vậy, để tránh né, bạn sẽ phải viết một cái gì đó như:
if($cb instanceof \Closure){}
Để làm điều này kiểm tra mỗi lần là vô nghĩa. Vì vậy, nếu bạn muốn sử dụng các phương thức đó nói rằng đối số là a closure
. Nếu không thì chỉ sử dụng bình thường.callback
. Cách này; Một lỗi được đưa ra khi gọi hàm thay vì mã của bạn khiến cho việc chẩn đoán dễ dàng hơn nhiều.
Trên một mặt lưu ý: Các closure
lớp không thể được mở rộng như nó thức .
["Foo", "bar"]
choFoo::bar
hoặc[$foo, "bar"]
cho$foo->bar
.