PHP中的闭包

  • 在PHP中闭包与匿名函数是一个概念;
$sayHello = function($name){
  echo("Hello $name");
};
  • 在PHP中闭包是像函数的对象,是个Closure类,只是能够像函数一样调用;
$sayHello("world");

输出 Hello world

var_dump($sayHello instanceof Closure);

输出 boolean(true)

  • 闭包在创建时就会为传入的参数、use中的变量创建新的内存,相当于clone一份,因此与函数外部的变量变化无关;
$name = 'world';

$sayHello = function() use($name){
  echo("Hello $name");
};//这里不要忘记结束的;号

$sayHello();//必须函数方式调用,即用(), 输出Hello world

$name = 'zj';

$sayHello();//输出 Hello world
  • 如果想使闭包内和外部的变量同步,则use中传入引用即可,就是加个&;
$name = 'world';

$sayHello = function() use(&$name){//传入了引用
  echo("Hello $name");
};//这里不要忘记结束的;号

$sayHello();//必须函数方式调用,即用(), 输出Hello world

$name = 'zj';

$sayHello();//输出 Hello zj
  • Closure类有两个方法:bind()和bindTo()

Closure::bind — 复制一个闭包,绑定指定的$this对象和类作用域。

Closure::bindTo — 复制当前闭包对象,绑定指定的$this对象和类作用域。

通过这两个方法可以给类扩展复杂功能,类似策略模式,将实际操作与类定义解耦。比如通过bing为用户类增加行为:

Class User{
	public $name = 'Tom';
	public $age = 10;
	private $action = [];

	//...
}
$sayHello = function(){
  echo("Hello {$this->name}\n");
};

$swimming = function(){
  echo("{$this->name} is swimming\n");
};

$bindSayHello = Closure::bind($sayHello, new User());
$bindSwimming = Closure::bind($swimming, new User());
$bindSayHello();
$bindSwimming();

输出: 

可以把类写的更优雅点:

Class user{
	public $name = 'Tom';
	public $age = 10;
	private $action = [];

	public function addAction($actionName, $actionFunction){
		$this->action[$actionName] = Closure::bind($actionFunction, $this);
	}

	public function doAction(){
		foreach ($this->action as $actionFunction) {
			$actionFunction($this->name);
		}
	}
}

$sayHello = function(){
  echo("Hello {$this->name}\n");
};

$swimming = function(){
  echo("{$this->name} is swimming\n");
};

$bindSayHello = Closure::bind($sayHello, new user());
$bindSayHello();


$user = new user();

$user->addAction('sayHello', $sayHello);
$user->addAction('swimming', $swimming);
$user->doAction();

bindTo方法与bind类似,只是通过闭包调用的,将自身绑定到对象或类上。

bind及bindTo方法都有第三个参数,确定绑定的作用域。

发现一个闭包实现中间件的例子,搬来作为补充学习:

--------------------- 以下内容来自『奔跑的码农』,感谢。

作者:奔跑的码农 
来源:优快云 
原文:https://blog.youkuaiyun.com/wuxing26jiayou/article/details/78069808 

<?php
// 框架核心应用层
$application = function($name) {
    echo "this is a {$name} application\n";
};
 
// 前置校验中间件
$auth = function($handler) {
    return function($name) use ($handler) {
        echo "{$name} need a auth middleware\n";
        return $handler($name);
    };
};
 
// 前置过滤中间件
$filter = function($handler) {
    return function($name) use ($handler) {
        echo "{$name} need a filter middleware\n";
        return $handler($name);
    };
};
 
// 后置日志中间件
$log = function($handler) {
    return function($name) use ($handler) {
        $return = $handler($name);
        echo "{$name} need a log middleware\n";
        return $return;
    };
};
 
// 中间件栈
$stack = [];
 
// 打包
function pack_middleware($handler, $stack)
{
    foreach (array_reverse($stack) as $key => $middleware) 
    {
        $handler = $middleware($handler);
    }
    return $handler;
}
 
// 注册中间件
// 这里用的都是全局中间件,实际应用时还可以为指定路由注册局部中间件
$stack['log'] = $log;
$stack['filter'] = $filter;
$stack['auth'] = $auth;
 
$run = pack_middleware($application, $stack);

输出:

Laravle need a filter middleware
Laravle need a auth middleware
this is a Laravle application
Laravle need a log middleware

打包程序

中间件的执行顺序是由打包函数(pack_middleware)决定,这里返回的闭包实际上相当于:

$run = $log($filter($auth($application)));
$run('Laravle');


编写规范
中间件要要满足一定的规范:总是返回一个闭包,闭包中总是传入相同的参数(由主要逻辑决定), 闭包总是返回句柄(handler)的执行结果;

如果中间件的逻辑在返回句柄return $handler($name)前完成,就是前置中间件,否则为后置中间件。

<think>好的,我现在需要回答用户关于PHP闭包函数的定义用法的问题。首先,我应该回顾用户提供的引用资料,看看面有哪些关键点。 根据引用[2],闭包函数也叫匿名函数,没有名字,主要用于回调函数的参数,是Closure类的实例,从PHP5.3开始引入。引用[1]提到闭包需要用use关键字或bindTo方法来附加状态,这与JS不同。引用[3][4]展示了闭包的基本语法使用use的例子,还有如何传递参数。 用户的问题集中在定义用法,所以需要分点说明。首先定义,然后基本语法,接着是用法比如作为回调、附加状态等。要注意强调闭包是对象,属于Closure类,这点可能其他语言不同,需要特别指出。 另外,用户提供的引用中有关于性能、优化应用场景的例子,但可能不需要在这展开,但如果有相关的用法可以提到。比如闭包作为回调在件处理中的应用。 需要确保使用正确的中文术语,比如“匿名函数”、“闭包”、“use关键字”、“bindTo方法”等。还要注意示例代码的正确性,比如在PHP闭包的声明调用方式,以及use的使用方法。 可能用户会混淆匿名函数闭包,需要解释它们的关系。在PHP中,闭包通常指匿名函数,但严格来说,闭包是能够捕获周围变量的匿名函数,所以需要使用use关键字。 需要检查是否有遗漏的关键点,比如闭包作为参数传递、返回闭包、以及bindTo方法在类中的作用。引用[1]提到bindTo可以为闭包增加状态,这可能涉及绑定到对象的作用域,这点可能需要举例说明。 最后,确保回答结构清晰,分点列出定义、语法、用法,每个部分有示例代码,并正确使用LaTeX格式,比如变量用$...$,代码块用反引号包裹。同时生成的相关问题要围绕闭包函数的特性、使用技巧实际应用来设计。</think>### PHP闭包函数的定义与用法 #### 一、定义与核心概念 PHP中的**闭包函数**(Closures)也称为**匿名函数**,是一种没有名称的函数,通常用于回调场景或作为参数传递。闭包PHP 5.3版本中正式引入,本质是`Closure`类的实例对象[^2][^4]。与普通函数不同,闭包可以捕获父作用域中的变量(通过`use`关键字),形成封闭的上下文环境[^1][^4]。 #### 二、基本语法 1. **创建闭包** 使用`function (...)`语法定义,并以分号结尾: ```php $closure = function ($a, $b) { return $a + $b; }; echo $closure(2, 3); // 输出 5 ``` 2. **捕获外部变量** 通过`use`关键字绑定父作用域的变量: ```php $x = 10; $closure = function ($y) use ($x) { return $x + $y; }; echo $closure(5); // 输出 15 ``` #### 三、关键特性与用法 1. **作为回调函数** 闭包常用于件处理、数组遍历等回调场景: ```php $numbers = [1, 2, 3]; array_walk($numbers, function ($value) { echo $value * 2; // 依次输出 2, 4, 6 }); ``` 2. **附加状态** PHP闭包需显式绑定外部变量,支持引用传递以修改外部值: ```php $count = 0; $closure = function () use (&$count) { $count++; }; $closure(); echo $count; // 输出 1 ``` 3. **对象属性与方法** 闭包是`Closure`类的实例,支持`bindTo`方法绑定作用域[^1]: ```php class Example { private $value = 100; } $closure = function () { return $this->value; }; $boundClosure = $closure->bindTo(new Example(), 'Example'); echo $boundClosure(); // 输出 100 ``` #### 四、注意项 - **变量捕获限制**:默认通过`use`捕获的变量是值传递,需用`&`符号实现引用传递。 - **作用域隔离**:闭包内部无法直接访问父作用域的变量,必须显式声明[^1]。 - **性能优化**:大量闭包可能增加内存开销,需谨慎使用。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

铭记北宸

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值