Sự khác biệt chính giữa chúng closurelà một lớp và callablemột loại .
Các callableloạ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 closuresẽ 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 closurelà 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 closurelớp không thể được mở rộng như nó thức .
["Foo", "bar"]choFoo::barhoặc[$foo, "bar"]cho$foo->bar.