本文目录导读:

- 闭包绑定与状态隔离(
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),是连接函数式与面向对象编程的桥梁。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播