PHP 5.3 版本引入了匿名函數,這是語言演進的重要里程碑。回顧各版本關鍵特性:
儘管 PHP 5.3 已發布多年,許多專案仍未充分運用匿名函數等新特性。
官方定義:匿名函數,又稱閉包,允許暫時建立一個無指定名稱的函數。最常作為回呼函數參數使用,也有其他應用場景。PHP 會自動將閉包表達式轉換為內建 Closure 類別的物件實例。
// 直接作為回呼函數使用
echo preg_replace_callback('~-([a-z])~', function ($match) {
return strtoupper($match[1]);
}, 'hello-world'); // 輸出 helloWorld
// 指派給變數(注意結尾需加分號)
$greet = function($name) {
printf("Hello %s\r\n", $name);
};
$greet('World'); // Hello World
$greet('PHP'); // Hello PHP
閉包預設無法存取外部變數,需透過 use 語法結構明確引入:
$message = 'hello';
// 未使用 use:無法存取外部變數
$example = function () {
var_dump($message); // Notice: Undefined variable
};
$example();
// 使用 use 繼承(值傳遞:定義時的值)
$example = function () use ($message) {
var_dump($message);
};
$example(); // string(5) "hello"
$message = 'world';
$example(); // 仍輸出 "hello",因為是值複製
// 參考傳遞:使用 & 符號
$example = function () use (&$message) {
var_dump($message);
};
$example(); // string(5) "hello"
$message = 'world';
$example(); // string(5) "world",反映父作用域最新值
// 結合一般參數與 use
$example = function ($arg) use ($message) {
var_dump($arg . ' ' . $message);
};
$example("hello"); // string(11) "hello world"
匿名函數本質上是變數指派,**必須先宣告才能使用**,這與具名函數(可前向呼叫)截然不同:
// 錯誤示範:先呼叫再宣告
echo $callback(); // Fatal error: Uncaught Error: Call to undefined function
$callback = function() { return "aa"; };
// 正確:先宣告再呼叫
$callback = function() { return "aa"; };
echo $callback(); // aa
// 具名函數不受此限制
function callback() { return "aa"; }
echo callback(); // aa
function callback() { return "aa"; } // 重複定義會報錯,但前向呼叫沒問題
這行為與 JavaScript 的函數表達式一致,開發時務必注意撰寫順序。
array_map、array_filter、array_reduce、usortClosure 類別提供靜態方法操作閉包:
Closure::bind($closure, $newThis, $newScope):綁定 $this 與作用域Closure::call($newThis, ...$args):臨時綁定並呼叫Closure::fromCallable($callable):從可呼叫物件建立閉包掌握匿名函數與閉包,能讓 PHP 程式碼更具彈性、模組化與表達力,是現代 PHP 開發不可或缺的技能。