Php有名函数绑定到匿名函数类上,PHP匿名函数,闭包

#在PHP中应用回调例子

如果对js非常熟悉的话,一定对匿名函数,回调等概念不陌生

```

$("#username").clcik(function(){

//code

$getJSON('/data.php', {name:name}, function(){

//远程获取数据

});

});

```

相信写js的人对上面的代码一定不陌生,同样,PHP之道的发起人写的`slim`框架,也在大量使用类似的语法,比如下面一段slim的代码

```

$app->get('/', function ($request, $response, $args) {

return $response->write("Hello " . $args['name']);

});

```

是不是写php跟写jQuery似的,非常有意思,Slim的作者是PHP和JavaScript程序员,同时也是《PHP The Right Way》的作者,相信js工程师也一定非常喜欢这样的语法。

#PHP创建闭包

注意,在PHP中,匿名函数(Anonymous functions),也叫闭包函数(closures),允许 临时创建一个没有指定名称的函数。最经常用作回调函数(callback)参数的值。当然,也有其它应用的情况。比如官网一个闭包函数的例子

```

echo preg_replace_callback('~-([a-z])~', function ($match) {

return strtoupper($match[1]);

}, 'hello-world');

// 输出 helloWorld

```

闭包函数也可以作为变量的值来使用。PHP 会自动把此种表达式转换成内置类 Closure 的对象实例。把一个 closure 对象赋值给一个`变量的方式`与普通变量赋值的语法是一样的,最后也要加上分号:

```

$add = function($a, $b){

return $a + $b;

};

echo $add(3,4);//输出7

```

注意,闭包函数构建了自己个一个作用域,如果需要使用父级作用域中的变量,必须使用`use`关键字

```

$message = 'hello';

$say1 = function(){

echo $message;

};

$say2 = function() use ($message){

echo $message;

}

$say1();//PHP Notice: Undefined variable: message

$say2();//hello

```

#闭包的本质

闭包和匿名函数其实就是伪装成函数的对象,如果审查PHP闭包或者匿名函数,你会发现它就是Closure类的实例,比如创建这个闭包

```

$add = function($a, $b){

return $a + $b;

};

echo $add(3,4);//输出7

```

闭包的情况是:

1. 创建一个闭包对象,这个对象继承Closure类

2. 实现Closure类中的__invoke()方法

2. 把闭包赋值给$add对象

3. 只要变量名后面有(),就立马调用__invoke()方法

比如下面这个例子证明闭包就是Closure类的实现

```

$add = function($a, $b){

return $a + $b;

};

var_dump($add instanceof Closure);//输出true

echo $add->__invoke(3,4);//输出7

```

或者再看一个例子,()会触发类的__invoke()方法

```

class Func{

function __invoke(){

echo 8888;

}

}

$func = new Func();

$func();//输出8888

```

#闭包实现路由回调

前面说到闭包有一个__invoke()魔术方法,但是,闭包还有一个方法,叫bindTo().这个方法可以吧Closure对象的内部状态绑定到其他对象上。bindTo方法的第二个参数很重要,作用是指定绑定闭包的那个对象所属的PHP类。基于这一点,我们可以使用bindTo()方法把路由URL映射到匿名回调函数上,框架会把匿名函数绑定到应用对象上,这么做之后就可以在匿名函数中使用$this关键字引用重要的应用对象

```

class App{

protected $routes = array();

protected $responseStatus = 200;

protected $responseContentType = 'text/html';

protected $responseBody = '';

public function addRoute($path, $call){

/**

* 第一个参数给匿名函数的一个对象,或者 NULL 来取消绑定。这里表示当前对象App

* 第二个参数关联到匿名函数的类作用域,这会决定绑定的对象的 保护、私有成员 方法的可见性,这一项保持可以访问protected属性

*/

$this->routes[$path] = $call -> bindTo($this, __CLASS__);

}

public function dispatch($curr_path){

foreach($this->routes as $path => $call){

if($path == $curr_path){

//执行回调函数

$call();

}

}

header('HTTP/1.1'. $this->responseStatus);

header('Content-type: '. $this->responseContentType);

header('Content-length: '. mb_strlen($this->responseBody));

echo $this->responseBody;

}

}

$app = new App();

$app -> addRoute('/', function(){

//由于这个匿名函数关联到了App类,这里的$this指向App这个实例

$this->responseContentType = 'application/json';

$this->responseBody = '{"name":"yongxiong"}';

});

$app -> dispatch('/');

```

测试这个路由App,使用PHP启动服务器

```

php -S localhost:9000

```

可以看到以下访问结果

13a039730b428eef35a03361655b88ee.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值