
// 定义一个简单的闭包
$greet = function($name) {
return "Hello, " . $name;
};
// 调用闭包
echo $greet("World"); // 输出: Hello, World
use
关键字实现:
$prefix = "Hello";
// 使用use捕获外部变量
$greet = function($name) use ($prefix) {
return $prefix . ", " . $name;
};
echo $greet("World"); // 输出: Hello, World
&
符号,闭包内部可以修改外部变量
$count = 0;
// 按引用捕获变量
$increment = function() use (&$count) {
$count++;
};
$increment();
$increment();
echo $count; // 输出: 2
use
关键字中指定的变量必须在闭包定义时就已存在&
)use ($var1, $var2, &$var3)
// 数组处理
$numbers = [1, 2, 3, 4, 5];
// 使用闭包作为array_map回调
$squared = array_map(function($n) {
return $n * $n;
}, $numbers);
// 结果: [1, 4, 9, 16, 25]
// 使用闭包作为usort回调
$people = [
['name' => 'Bob', 'age' => 30],
['name' => 'Alice', 'age' => 25]
];
usort($people, function($a, $b) {
return $a['age'] - $b['age'];
});
// 按年龄排序后的数组
// 数据过滤逻辑封装
function createFilter($allowedFields) {
// 返回一个闭包作为过滤器
return function($data) use ($allowedFields) {
return array_intersect_key($data, array_flip($allowedFields));
};
}
// 创建只允许特定字段的过滤器
$userFilter = createFilter(['name', 'email']);
// 使用过滤器
$inputData = [
'name' => 'John',
'email' => 'john@example.com',
'password' => 'secret', // 这个字段会被过滤掉
'role' => 'admin' // 这个字段会被过滤掉
];
$filteredData = $userFilter($inputData);
// 结果: ['name' => 'John', 'email' => 'john@example.com']
// 日志记录器,延迟执行日志写入
class Logger {
private $queue = [];
// 添加日志任务到队列
public function addLog($message, $level = 'info') {
$this->queue[] = function() use ($message, $level) {
$timestamp = date('Y-m-d H:i:s');
return "[$timestamp] [$level] $message";
};
}
// 执行所有日志任务并写入文件
public function flush($filename) {
$content = '';
foreach ($this->queue as $task) {
$content .= $task() . "\n";
}
file_put_contents($filename, $content, FILE_APPEND);
$this->queue = [];
}
}
// 使用示例
$logger = new Logger();
$logger->addLog('User login', 'info');
$logger->addLog('Failed payment', 'error');
// 其他操作...
// 最后统一写入日志
$logger->flush('app.log');
// 创建一个比较函数工厂
function createComparator($field, $direction = 'asc') {
return function($a, $b) use ($field, $direction) {
if ($a[$field] == $b[$field]) {
return 0;
}
$result = ($a[$field] < $b[$field]) ? -1 : 1;
return $direction === 'desc' ? -$result : $result;
};
}
// 创建按价格升序的比较器
$priceAsc = createComparator('price');
// 创建按名称降序的比较器
$nameDesc = createComparator('name', 'desc');
$products = [
['name' => 'Laptop', 'price' => 999],
['name' => 'Phone', 'price' => 699],
['name' => 'Tablet', 'price' => 299]
];
// 使用不同的比较器排序
usort($products, $priceAsc); // 按价格升序
usort($products, $nameDesc); // 按名称降序
class User {
private $name;
private $email;
public function __construct($name, $email) {
$this->name = $name;
$this->email = $email;
}
}
$user = new User("John Doe", "john@example.com");
// 创建一个闭包,尝试访问对象的私有属性
$getUserInfo = function() {
return [
'name' => $this->name,
'email' => $this->email
];
};
// 将闭包绑定到$user对象
$bound = $getUserInfo->bindTo($user, $user);
$info = $bound();
// 结果: ['name' => 'John Doe', 'email' => 'john@example.com']
// PHP 7.0+ 更简洁的call()方法
$info = $getUserInfo->call($user);
bindTo()
方法的第二个参数指定了闭包的作用域,可以是类名或对象。static
关键字定义的静态闭包不能访问$this
:
class Example {
private $value = 10;
public function getClosure() {
// 静态闭包
return static function() {
// 错误:静态闭包中不能使用$this
// return $this->value;
return "This is a static closure";
};
}
}
ReflectionFunction
类获取闭包的信息:
$closure = function($a, $b) {
return $a + $b;
};
$reflection = new ReflectionFunction($closure);
echo "参数数量: " . $reflection->getNumberOfParameters() . "\n"; // 输出: 2
echo "参数1类型: " . $reflection->getParameters()[0]->getName() . "\n"; // 输出: a
// 推荐:简洁的闭包
$filter = function($item) {
return $item['active'] && $item['score'] > 80;
};
// 不推荐:过于复杂的闭包
$complex = function($data) {
// 大量逻辑...
// 嵌套循环...
// 条件判断...
};
// 推荐:只捕获需要的变量
$processor = function($data) use ($requiredFields) {
// 处理逻辑
};
// 不推荐:捕获过多不必要的变量
$bad = function() use ($a, $b, $c, $d, $e, $f) {
// 只使用了$a和$c
};
$calculator = function(int $a, int $b): int {
return $a + $b;
};
$filter = function(array $item): bool {
return isset($item['id']) && is_numeric($item['id']);
};
// 复杂场景使用匿名类更合适
$counter = new class {
private $count = 0;
public function increment() {
$this->count++;
}
public function getCount() {
return $this->count;
}
};
$counter->increment();
$counter->increment();
echo $counter->getCount(); // 输出: 2
$this
使用$this
,需要显式捕获:
class MyClass {
private $value = 5;
public function getClosure() {
// 显式捕获$this
return function() {
return $this->value;
};
}
}
$obj = new MyClass();
$closure = $obj->getClosure();
echo $closure(); // 输出: 5 (PHP 5.4+ 支持)
$closure = function() {
return "Hello";
};
// 错误:Uncaught Exception: Serialization of 'Closure' is not allowed
serialize($closure);
__serialize
和__unserialize
方法手动处理,或避免序列化闭包。
// 性能敏感场景优先使用普通函数
function processItem($item) {
// 处理逻辑
}
// 而非闭包
$processor = function($item) {
// 处理逻辑
};
// 特别是在循环中
foreach ($largeArray as $item) {
processItem($item); // 比使用闭包略快
}