PHP 無「函數型別」,函數名在非呼叫情境下會被解析為字串:
$func = 'strlen'; // 正確賦值方式
$func(); // 動態呼叫
call_user_func('strlen', 'test'); // 替代呼叫方式
此機制導致所有函數皆為全域,不支援重複定義,也無法像 JavaScript 那樣在執行期重新定義函數行為。
利用 PHP 的「變數變數」特性或 call_user_func() 陣列格式:
class Controller {
public function login() { echo "Login"; }
}
$action = 'login';
$controller = new Controller();
$controller->$action(); // 物件方法
Controller::$action(); // 靜態方法
call_user_func(array('Controller', $action)); // 靜態方法回呼
call_user_func(array($controller, $action)); // 實例方法回呼
PHP 5.2.3+ 支援 'Class::method' 字串格式;PHP 5.3+ 引入命名空間後需加前綴:__NAMESPACE__ . '::Class::method'。
$lambda = create_function('$a', 'return addslashes(trim($a));');
// 實際產生全域函數,名稱如 "\0lambda_1",無法真正捕獲外部變數
缺點:程式碼寫在字串中難維護、效能差、無法實作真正閉包。
$data = range(0, 10);
$newData = array_map(function($v) {
$a = range(0, $v);
return array_sum($a);
}, $data);
// 真正的閉包:使用 use 關鍵字捕獲外部變數
function outer() {
$a = 123;
return function() use ($a) { echo $a; }; // 值捕獲(複製)
}
$inner = outer();
$inner(); // 輸出 123
function outer() {
$a = 0;
return function() use ($a) { return $a++; }; // 每次呼叫都輸出 0(值複製)
}
$inner = outer();
$inner(); // 0
$inner(); // 0
// 解決:引用捕獲
function outer() {
$a = 0;
return function() use (&$a) { return $a++; }; // 正確遞增
}
$inner = outer();
$inner(); // 0
$inner(); // 1
$inner(); // 2
PHP 內建 array_map、array_filter、array_reduce、array_walk 等高階函數,支援函數式資料處理風格:
array_walk($_REQUEST, 'trim'); // 對所有請求參數執行 trim