本文目录导读:

- 闭包绑定与状态隔离(
bindTo与bind) - 闭包作为“微对象”实现状态(use 引用)
- 延迟执行与惰性加载
- 函数式编程:柯里化(Currying)与部分应用
- 闭包实现“策略模式”的轻量版本
- 与
__invoke配合:可调用的类 - 闭包与
Generator结合:实现协程或无限序列
在 PHP 中,闭包(Closure)不仅仅是简单的匿名函数,它有很多高级用法,特别是在现代 PHP 框架和设计模式中非常常见。
以下是几个高级用法及其代码示例:
闭包绑定与状态隔离(bindTo 与 bind)
这是 PHP 闭包最强大的特性之一,你可以将一个闭包绑定到不同的对象上,从而改变其内部的 $this。
class Counter {
private int $count = 0;
}
$increment = function (int $step = 1) {
// 这里的 $this 取决于绑定的对象
$this->count += $step;
return $this->count;
};
$counter1 = new Counter();
$counter2 = new Counter();
// 将闭包绑定到 counter1
$inc1 = Closure::bind($increment, $counter1);
// 将闭包绑定到 counter2
$inc2 = Closure::bind($increment, $counter2);
echo $inc1(1); // 1
echo $inc1(2); // 3
echo $inc2(5); // 5 (独立于 counter1)
echo $inc1(1); // 4 (counter1 继续)
高级技巧:使用 bindTo 可以绑定作用域,访问私有属性:
$getPrivate = function () {
return $this->secret;
};
$obj = new class {
private string $secret = 'hidden';
};
// 第二个参数指定作用域(类名),允许访问私有属性
$bound = $getPrivate->bindTo($obj, $obj::class);
echo $bound(); // hidden
闭包作为“微对象”实现状态(use 引用)
利用闭包捕获外部变量的特性,可以创建类似“有状态的对象”而无需定义类:
function createCounter(): Closure {
$count = 0;
return function (int $step = 1) use (&$count) {
$count += $step;
return $count;
};
}
$counter = createCounter();
echo $counter(); // 1
echo $counter(5); // 6
echo $counter(); // 7
高级变体:返回多个方法
function createUser(string $name): array {
$data = ['name' => $name, 'age' => 0];
return [
'getName' => function () use ($name) {
return $name;
},
'setAge' => function (int $age) use (&$data) {
$data['age'] = $age;
},
'getAge' => function () use (&$data) {
return $data['age'];
}
];
}
$user = createUser('Alice');
echo $user['getName'](); // Alice
$user['setAge'](25);
echo $user['getAge'](); // 25
延迟执行与惰性加载
闭包可以延迟耗时的计算,直到真正需要结果时:
class HeavyResource {
public function __construct() {
sleep(2); // 模拟耗时加载
$this->data = 'heavy data';
}
public function getData(): string {
return $this->data;
}
}
class LazyContainer {
private ?Closure $loader = null;
private ?HeavyResource $instance = null;
public function __construct() {
// 只保存闭包,不执行
$this->loader = function () {
return new HeavyResource();
};
}
public function getResource(): HeavyResource {
if ($this->instance === null) {
// 首次调用才真正执行
$this->instance = ($this->loader)();
}
return $this->instance;
}
}
$container = new LazyContainer(); // 立即返回,不阻塞
// ... 其他代码 ...
echo $container->getResource()->getData(); // 这里才真正加载
函数式编程:柯里化(Currying)与部分应用
// 柯里化:将多参数函数转化为单参数链
function curry(callable $fn, int $arity): Closure {
$args = [];
return function (...$input) use ($fn, $arity, &$args) {
$args = array_merge($args, $input);
if (count($args) >= $arity) {
$result = $fn(...$args);
$args = [];
return $result;
}
// 返回自身等待更多参数
return fn(...$more) => $this(...$more);
};
}
$add = fn($a, $b, $c) => $a + $b + $c;
$curriedAdd = curry($add, 3);
$add5 = $curriedAdd(5); // 等待剩余2个参数
$add5And3 = $add5(3); // 等待最后1个参数
echo $add5And3(2); // 10
闭包实现“策略模式”的轻量版本
不需要定义接口和实现类,直接用闭包作为策略:
class PriceCalculator {
private Closure $discountStrategy;
public function __construct(Closure $strategy) {
$this->discountStrategy = $strategy;
}
public function calculate(float $basePrice): float {
return ($this->discountStrategy)($basePrice);
}
}
// 定义不同的策略(闭包)
$noDiscount = fn($price) => $price;
$tenPercentOff = fn($price) => $price * 0.9;
$fixedDiscount = fn($price) => max(0, $price - 10);
$calculator = new PriceCalculator($tenPercentOff);
echo $calculator->calculate(100); // 90
// 运行时轻松切换策略
$calc2 = new PriceCalculator($fixedDiscount);
echo $calc2->calculate(100); // 90
与 __invoke 配合:可调用的类
将类设计为可调用,并利用闭包或内部逻辑:
class EventDispatcher {
private array $listeners = [];
public function on(string $event, Closure $handler): void {
$this->listeners[$event][] = $handler;
}
public function __invoke(string $event, mixed $data = null): void {
foreach ($this->listeners[$event] ?? [] as $handler) {
$handler($data);
}
}
}
$dispatcher = new EventDispatcher();
$dispatcher->on('login', function ($user) {
echo "User {$user} logged in\n";
});
$dispatcher->on('login', function ($user) {
// 第二个监听器
echo "Send welcome email to {$user}\n";
});
// 直接调用对象
$dispatcher('login', 'Alice');
闭包与 Generator 结合:实现协程或无限序列
function createLazySequence(Closure $generator): Closure {
return function () use ($generator) {
$iterator = $generator();
return function () use (&$iterator) {
if ($iterator->valid()) {
$current = $iterator->current();
$iterator->next();
return $current;
}
return null;
};
};
}
$fibonacci = function () {
$a = 0;
$b = 1;
while (true) {
yield $a;
[$a, $b] = [$b, $a + $b];
}
};
$getNext = createLazySequence($fibonacci)();
echo $getNext(); // 0
echo $getNext(); // 1
echo $getNext(); // 1
echo $getNext(); // 2
echo $getNext(); // 3
echo $getNext(); // 5
| 特性 | 使用场景 |
|---|---|
Closure::bind/bindTo |
访问私有属性、模拟依赖注入、AOP编程 |
use 引用传递 |
创建有状态闭包、简单状态管理 |
| 延迟加载 | 性能优化、按需创建资源 |
| 柯里化 | 函数组合、参数预填充 |
| 策略模式 | 替代大量子类,灵活切换算法 |
| 可调用类 | 事件系统、中间件链 |
闭包在 PHP 中的本质是 Closure 类的实例,这使得它既有函数的行为,又有对象的方法(如 bindTo),是连接函数式与面向对象编程的桥梁。