PHP 5.3 引入閉包(Closure),即匿名函數,極大豐富了函數式編程能力。本文系統講解閉包語法、use 綁定機制、經典應用場景(計數器、遞歸解耦、延遲綁定),並附帶 array_walk 等內建函數結合示例。
use 關鍵字$a = function() use($b) { /* ... */ };
use 將外部作用域變量「捕獲」到閉包內部。默認按值捕獲(複製),加 & 為引用捕獲。
<?php
$msg = "Hello, everyone";
$fun = function () use($msg) {
print "msg is: $msg. <br />";
};
$msg = "Hello, everybody"; // 修改外部變量
$fun(); // 輸出: msg is: Hello, everyone. (值捕獲,創建時拷貝)
// 引用捕獲
$msg = "Hello";
$funRef = function () use(&$msg) { print $msg; };
$msg = "World";
$funRef(); // 輸出: World
?>
利用閉包「攜帶」自由變量狀態:
<?php
function counter() {
$counter = 1;
return function() use(&$counter) { return $counter++; };
}
$c1 = counter(); $c2 = counter();
echo $c1(); // 1
echo $c1(); // 2
echo $c2(); // 1(獨立狀態)
?>
每次調用 counter() 創建新的 $counter 和閉包,兩者互不干擾。
array_walk 回調購物車計算總價,閉包捕獲 $tax 和 $total(引用):
<?php
class Cart {
const PRICE_BUTTER = 1.00; const PRICE_MILK = 3.00; const PRICE_EGGS = 6.95;
protected $products = [];
public function add($product, $qty) { $this->products[$product] = $qty; }
public function getTotal($tax) {
$total = 0.00;
$callback = function ($qty, $product) use ($tax, &$total) {
$price = constant(__CLASS__ . '::PRICE_' . strtoupper($product));
$total += ($price * $qty) * ($tax + 1.0);
};
array_walk($this->products, $callback);
return round($total, 2);
}
}
$cart = new Cart();
$cart->add('butter', 1); $cart->add('milk', 3); $cart->add('eggs', 6);
echo $cart->getTotal(0.05); // 54.29
?>
避免了 foreach 並在回調中直接修改外部 $total。
匿名函數需引用自身調用,必須用 use(&$fn):
<?php
$fib = function($n) use(&$fib) {
if ($n == 0 || $n == 1) return 1;
return $fib($n - 1) + $fib($n - 2);
};
echo $fib(5); // 8
// 通用模式
$recursive = function () use (&$recursive) { /* ... */ };
?>
若不加 &,$fib($n-1) 會找不到函數(定義時 $fib 尚未賦值完成)。
<?php
$result = 0;
$one = function() { var_dump($result); }; // 未捕獲,報錯 NULL
$two = function() use ($result) { var_dump($result); }; // 值捕獲,輸出 0
$three = function() use (&$result) { var_dump($result); }; // 引用捕獲,輸出 1
$result++;
$one(); $two(); $three();
?>
use(&$var) 實現「調用時賦值」,use($var) 為「定義時拷貝」。
閉包是 PHP 函數式編程的基石,核心在於 use 的捕獲策略。掌握值/引用捕獲、延遲綁定、遞歸自引用,即可編寫優雅的回調、工廠函數、狀態封裝等模式。PHP 7.4+ 更引入箭頭函數 fn() => ... 自動按值捕獲外部變量,進一步簡化語法。