Higher Order PHP - start from callback
Wed, 22 Jul 2009 00:00:06 +0800PHP 5.3.0開始,有一個重要的特性正式加到PHP裡面,就是匿名函數。(請參考:Anonymous functions。手冊還有提到,匿名函數目前是用 Closure內部類別實作,但是不要管他,因為實作方式有可能修改。)
在提到匿名函數之前,先看看PHP的callback應用。callback是php非常好用的功能,可以利用他來用自訂的方式處理資料,例如array_map,就可以用一個callback函數一次處理陣列中所有元素,不用iteration,也不用loop。下面是用callback函數處理一個整數陣列,傳回每個元素的平方:
function power($v) { return $v*$v; } print_r(array_map("power", range(1,10)));
結果是:
Array ( [0] => 1 [1] => 4 [2] => 9 [3] => 16 [4] => 25 [5] => 36 [6] => 49 [7] => 64 [8] => 81 [9] => 100 )
在php 5.3定義匿名函數很簡單,底下是一個例子:
$func = function ($name) { echo "\"anonymous function invoked with params: ".$name; }; $func("hello anonymous function\n\"");
像這樣可以把一個匿名函數指派給$func變數,然後透過$func變數就可以使用。執行結果如下:
"anonymous function invoked with params: hello anonymous function"
一般的場合大概比較少這樣用就是了(看習慣)。PHP 5.3.0之前的版本,callback函數要用字串來指派,到了PHP 5.3.0則可以直接用匿名函數來指派。透過匿名函數定義中新增的use語法來運用外層scope的變數,就可以完整使用到Closure的便利性。以array_map為例,之前的callback只能針對個別元素做處理,如果你想做做出所有元素累加的功能,就會被迫使用global變數,這樣既不優雅,又缺乏重用性。利用Closure就可以用簡潔的語法做出這樣的功能:
function sumUp() { $init = 0; return function ($v) use(&$init) { $init += $v; return $init; }; } print_r (array_map(sumUp(), range(1,5))); print_r(array_map(sumUp(), range(1,10)));
這樣執行的結果是:
Array ( [0] => 1 [1] => 3 [2] => 6 [3] => 10 [4] => 15 ) Array ( [0] => 1 [1] => 3 [2] => 6 [3] => 10 [4] => 15 [5] => 21 [6] => 28 [7] => 36 [8] => 45 [9] => 55 )
雖然用起來還是有點囉唆(要用use來宣告要用到的外層變數),不過PHP的表現力又往前進了一大步。在上面的例子也展示了Higher Order Function的特性:函數可以當作變數傳遞,可以當作傳給函數的參數,也可以當作函數的返回值。