callback, anonymous function and closure
/ 4 min read
Table of Contents
聊聊這三個東西在 php 裡的差異好了
callback
callback,是指任何可以 callable 的程式片段,無論是 php 原生的 function,自己寫的 function、class 的 method,亦或是 closure
,只要他是 callable 的就好,for example:
echoString 是一個 callable 的 function, 所以為 callback
funcion echoString ($string){ echo $string . PHP_EOL;}call_user_func('echoString', 'php awesome !');
myEcho::string() 是一個 callable 的 method, 所以他也是 callback
class myEcho{ public static function string($string) { echo $string . PHP_EOL; }}call_user_func(['myEcho', 'string'], 'php awesome !');
也可以使用 php 原生的 function,只要是 callable 的,就是 callback
stringList = ['php','awesome'];$result = array_filter($stringList, 'is_int');
var_export($result);
在這個例子裡, $echoString 是個 callable 的 closure,所以也可以稱它為 callback
$stringList = ['php','awesome'];$echoString = function ($string) { echo $string . PHP_EOL;};
array_walk($stringList, $echoString);
anonymous function
php 5.3 後引入的東西,他讓你可以讓函示隨意指派給某個變數,只是最後還是用 closure 來實作,for example
// anonymous function, 沒有 function name$isInteger = function ($integer) { return is_int($integer);};
// 會發現到他是 closure 的 instancevar_export($isInteger);
// 因為他是 callable 的,所以都可以做到 callback 可以做的事情$stringList = ['php','awesome'];$result = array_filter($stringList, $isInteger);
var_export($result);
closure
這就是匿名函式的實作方法,也就是為了要做到 anonymous function,就必須要有 closure 來幫你處理這件事,他有幾個特性:
變數的 scope 的限制, 所以下面的例子裡, $stock 會被暫存下來
$setStock = function ($default) { $stock = $default; return function () use (&$stock) { $stock --; if (1 > $stock) { echo 'out of stock !'; return; } return $stock; };};
$sold = $setStock(3);echo $sold() . PHP_EOL;echo $sold() . PHP_EOL;echo $sold() . PHP_EOL;echo $sold() . PHP_EOL;
currying
$currying = function ($default) { return function ($integer) use ($default) { return $default += $integer; };};
// 這看起來有沒有很像 js 的感覺?echo $currying(1)(1) . PHP_EOL;echo $currying(2)(1) . PHP_EOL;echo $currying(3)(1) . PHP_EOL;
所以需要注意 type hint
由上面的例子可以知道,anonymous function 的 type hint 有兩種,分別為 Closure
以及 Callble
,而 php 原生的 function 只有 Callable
,可以看看下面的例子會因為 type hint 的差異而有所不同
如果是 callable 的話,就不會有問題
class MyString{ // 注意這邊的 type hint 為 callable public function test($string, Callable $function) { $isString = $function($string); echo ($isString) ? 'yes' : 'no'; echo PHP_EOL; }}
$myString = new MyString;
// 使用 php 原生 function$myString->test('I_AM_STRING', 'is_string');
// 或者 anonymous function$myString->test('I_AM_STRING', function($string) { return is_string($string);});
如果是 Closure 的話,就要注意 php 原生 function 的問題了
class MyString{ // 注意這邊的 type hint 為 callable public function test($string, Closure $function) { $isString = $function($string); echo ($isString) ? 'yes' : 'no'; echo PHP_EOL; }}
$myString = new MyString;
// 使用 php 原生 function,你會得到 type hint 錯誤的訊息// $myString->test('I_AM_STRING', 'is_string');
// 但是還是可以修改成這樣,只是 php 7.1 以上限定 XD// $myString->test('I_AM_STRING', Closure::fromCallable('is_string'));
// 所以如果遇到 type hint 為 closure 的話,還是把 `is_string` 用 anonymous function 包起來吧$myString->test('I_AM_STRING', function($string) { return is_string($string);});