本文目录导读:

PHP 闭包(Closure)也称为匿名函数,是PHP中非常强大的特性,让我详细介绍它的用法:
基本语法
<?php
// 基础闭包
$greet = function($name) {
echo "Hello, " . $name . "!\n";
};
$greet('World'); // 输出: Hello, World!
use 关键字使用外部变量
<?php
$message = 'Hello';
$greet = function($name) use ($message) {
echo $message . ', ' . $name . "!\n";
};
$greet('PHP'); // 输出: Hello, PHP!
// use 按值传递(拷贝)
$number = 1;
$add = function() use ($number) {
$number++;
echo $number . "\n";
};
$add(); // 输出: 2
echo $number; // 输出: 1 (原值不变)
// 使用 & 按引用传递
$number = 1;
$add = function() use (&$number) {
$number++;
echo $number . "\n";
};
$add(); // 输出: 2
echo $number; // 输出: 2 (值已改变)
作为回调函数使用
<?php
// 数组处理
$numbers = [1, 2, 3, 4, 5];
// 使用 array_map
$squared = array_map(function($n) {
return $n * $n;
}, $numbers);
print_r($squared); // [1, 4, 9, 16, 25]
// 使用 array_filter
$even = array_filter($numbers, function($n) {
return $n % 2 == 0;
});
print_r($even); // [2, 4]
// 使用 usort
$fruits = ['apple', 'Orange', 'banana'];
usort($fruits, function($a, $b) {
return strcmp(strtolower($a), strtolower($b));
});
print_r($fruits); // ['apple', 'banana', 'Orange']
作为函数参数传递
<?php
// 定义接受闭包的函数
function processData($data, $callback) {
$result = [];
foreach ($data as $item) {
$result[] = $callback($item);
}
return $result;
}
$numbers = [1, 2, 3, 4];
// 传入闭包
$doubled = processData($numbers, function($n) {
return $n * 2;
});
print_r($doubled); // [2, 4, 6, 8]
返回闭包(工厂模式)
<?php
// 创建一个乘法器
function createMultiplier($factor) {
return function($number) use ($factor) {
return $number * $factor;
};
}
$double = createMultiplier(2);
$triple = createMultiplier(3);
echo $double(5); // 输出: 10
echo $triple(5); // 输出: 15
绑定 $this(闭包绑定)
<?php
class User {
private $name;
public function __construct($name) {
$this->name = $name;
}
public function getName() {
return $this->name;
}
}
$user = new User('Alice');
// 创建闭包
$closure = function() {
return $this->getName();
};
// 绑定闭包到对象
$bound = $closure->bindTo($user);
echo $bound(); // 输出: Alice
// 使用 Closure::call (PHP 7+)
echo $closure->call($user); // 输出: Alice
箭头函数(PHP 7.4+)
<?php
// 箭头函数简洁语法
$factor = 10;
$numbers = [1, 2, 3];
// 传统闭包
$result1 = array_map(function($n) use ($factor) {
return $n * $factor;
}, $numbers);
// 箭头函数
$result2 = array_map(fn($n) => $n * $factor, $numbers);
print_r($result1); // [10, 20, 30]
print_r($result2); // [10, 20, 30]
实际应用示例
<?php
// 示例1:构建灵活的过滤系统
class ProductFilter {
private $products;
public function __construct($products) {
$this->products = $products;
}
public function filter($callback) {
return array_filter($this->products, $callback);
}
}
$products = [
['name' => 'Laptop', 'price' => 999],
['name' => 'Mouse', 'price' => 25],
['name' => 'Keyboard', 'price' => 50]
];
$filter = new ProductFilter($products);
// 找到价格低于100的产品
$cheapProducts = $filter->filter(function($product) {
return $product['price'] < 100;
});
print_r($cheapProducts);
// 示例2:事件系统
class EventEmitter {
private $listeners = [];
public function on($event, $callback) {
$this->listeners[$event][] = $callback;
}
public function emit($event, $data = null) {
if (isset($this->listeners[$event])) {
foreach ($this->listeners[$event] as $callback) {
$callback($data);
}
}
}
}
$emitter = new EventEmitter();
$emitter->on('user_login', function($user) {
echo "用户 {$user} 登录了\n";
});
$emitter->on('user_login', function($user) {
echo "记录登录日志: {$user}\n";
});
$emitter->emit('user_login', '张三');
闭包的常用方法
<?php
$closure = function($param) {
return $param * 2;
};
// 检查类型
echo get_class($closure); // Closure
// 使用反射
$reflection = new ReflectionFunction($closure);
echo $reflection->getNumberOfParameters(); // 1
echo $reflection->getName(); // {closure}
// bind/bindTo 方法
$boundClosure = Closure::bind($closure, null, 'SomeClass');
注意事项
<?php
// 1. use 捕获变量时是副本
$var = 'outside';
$closure = function() use ($var) {
echo $var;
};
$var = 'changed';
$closure(); // 输出: outside
// 2. 作用域问题
$prev = function() {
// 无法访问外部变量,除非使用 use
// echo $externalVar; // 错误
};
// 3. 递归闭包需要显式声明
$factorial = function($n) use (&$factorial) {
if ($n <= 1) return 1;
return $n * $factorial($n - 1);
};
echo $factorial(5); // 120
闭包在PHP中的主要用途:
- 回调函数
- 函数式编程
- 事件处理
- 依赖注入
- 状态封装
- 延迟计算
掌握闭包可以让你写出更灵活、更简洁的代码,在面向对象和函数式编程之间架起桥梁。