PHP: Type hinting-разница между 'Closure' и ' Callable`
я заметил, что я могу использовать Closure
или Callable
как подсказка типа, если мы ожидали некоторую функцию обратного вызова для запуска. Например:
function callFunc1(Closure $closure) {
$closure();
}
function callFunc2(Callable $callback) {
$callback();
}
$function = function() {
echo 'Hello, World!';
};
callFunc1($function); // Hello, World!
callFunc2($function); // Hello, World!
вопрос:
какая здесь разница ? Другими словами, когда использовать Closure
и когда использовать Callable
или они служат той же цели ?
3 ответа:
разница в том, что
Closure
должна быть анонимная функция, гдеcallable
также может быть обычной функцией.вы можете увидеть/проверить это на примере ниже, и вы увидите, что вы получите ошибку для первого:
function callFunc1(Closure $closure) { $closure(); } function callFunc2(Callable $callback) { $callback(); } function xy() { echo 'Hello, World!'; } callFunc1("xy"); // Catchable fatal error: Argument 1 passed to callFunc1() must be an instance of Closure, string given callFunc2("xy"); // Hello, World!
поэтому, если вы хотите только ввести анонимную функцию подсказки, используйте:
Closure
и если вы хотите также разрешить использование обычных функцийcallable
типа намек.
основное различие между ними заключается в том, что
closure
это класс иcallable
a тип.The
callable
тип принимает все, что может быть под названием:var_dump( is_callable('functionName'), is_callable([$myClass, 'methodName']), is_callable(function(){}) );
где a
closure
будет только принять анонимную функцию. Обратите внимание, что в PHP версии 7.1 вы можете конвертировать функции в закрытие следующим образом:Closure::fromCallable('functionName')
.
пример:
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 }
так зачем использовать
closure
overcallable
?строгость, потому что a
closure
- это объект, который имеет некоторые дополнительные методы:call()
,bind()
иbindto()
. Они позволяют использовать функцию, объявленную вне класса, и выполнять ее так, как если бы она была внутри класса.$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
вы не хотели бы вызывать методы на нормальный функция как таковая вызовет фатальные ошибки. Так что для того, чтобы обойти это вам придется написать что-то вроде:
if($cb instanceof \Closure){}
делать эту проверку каждый раз бессмысленно. Поэтому, если вы хотите использовать эти методы, укажите, что аргумент является
closure
. В противном случае просто используйте нормальныйcallback
. Таким образом; ошибка возникает при вызове функции вместо вашего кода, что делает его гораздо проще диагностировать.на заметку: The
closure
класс не может быть расширен как его финал.
стоит отметить, что это не будет работать для PHP версий 5.3.21-5.3.29.
в любой из этих версий вы получите результат:
Привет, Мир! Уловимая фатальная ошибка: Аргумент 1, передаваемый в callFunc2 (), должен быть экземпляром > Callable, экземпляром заданного закрытия, вызываемым в /в/kqeYD в строке 16 и определяемым в /в/kqeYD в строке 7
процесс завершается с кодом 255.
можно попробовать через https://3v4l.org/kqeYD#v5321
с уважением,