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方法都有第三个参数,确定绑定的作用域。

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

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

作者:奔跑的码农 
来源:CSDN 
原文:https://blog.csdn.net/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)前完成,就是前置中间件,否则为后置中间件。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

铭记北宸

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

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

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

打赏作者

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

抵扣说明:

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

余额充值