added cactus theme files
This commit is contained in:
@@ -0,0 +1,119 @@
|
||||
---
|
||||
title: php的闭包特性
|
||||
date: 2017-01-11 18:39:17
|
||||
category: notes
|
||||
tags:
|
||||
- php
|
||||
keywords:
|
||||
- php
|
||||
- 闭包
|
||||
- lambada
|
||||
- 匿名函数
|
||||
---
|
||||
|
||||
闭包和匿名函数在`PHP 5.3.0`引入,并且PHP将两者视为相同的概念。闭包其实是伪装成函数的对象,它的实质其实是`Closure`实例。
|
||||
|
||||
创建闭包非常简单:
|
||||
|
||||
```php
|
||||
$c = function($name) {
|
||||
return sprintf("Hello World! Hello %s!", $name);
|
||||
};
|
||||
|
||||
echo $c('PHP');
|
||||
```
|
||||
|
||||
使用`use`对闭包附加状态,多个参数使用`,`分隔:
|
||||
|
||||
```php
|
||||
function callPerson($name) {
|
||||
return function($about) use ($name) {
|
||||
return sprintf("%s, %s", $name, $about);
|
||||
}
|
||||
}
|
||||
|
||||
$triver = callPerson('Triver');
|
||||
echo $triver("slow down, please!!");
|
||||
|
||||
```
|
||||
|
||||
附加的变量会被封装到闭包内,即使返回的闭包队形已经跳出了`callPerson()`的作用域也仍然会记住`$name`的值。
|
||||
|
||||
闭包有一个有趣的`bindTo()`方法,可以将闭包的内部状态绑定到其他对象上,第二个参数指定了绑定闭包的对象所属的类,从而实现在闭包中访问绑定对象的私有方法和属性。
|
||||
|
||||
```php
|
||||
class Bind {
|
||||
protected $name = 'no name';
|
||||
public $change;
|
||||
|
||||
public function addAction($action) {
|
||||
$this->change = $action->bindTo($this, __CLASS__);
|
||||
}
|
||||
}
|
||||
|
||||
$bind = new Bind();
|
||||
$bind->addAction(function() {
|
||||
$this->name = "php";
|
||||
return $this->name;
|
||||
});
|
||||
|
||||
$change = $bind->change;
|
||||
echo $change();
|
||||
```
|
||||
|
||||
使用这个特性可以方便的为类添加方法并绑定:
|
||||
|
||||
```php
|
||||
trait MetaTrait
|
||||
{
|
||||
//定义$methods数组,用于保存方法(函数)的名字和地址。
|
||||
private $methods = array();
|
||||
//定义addMethod方法,使用闭包类绑定匿名函数。
|
||||
public function addMethod($methodName, $methodCallable)
|
||||
{
|
||||
if (!is_callable($methodCallable)) {
|
||||
throw new InvalidArgumentException('Second param must be callable');
|
||||
}
|
||||
$this->methods[$methodName] = Closure::bind($methodCallable, $this, get_class());
|
||||
}
|
||||
//方法重载。为了避免当调用的方法不存在时产生错误,
|
||||
//可以使用 __call() 方法来避免。
|
||||
public function __call($methodName, array $args)
|
||||
{
|
||||
if (isset($this->methods[$methodName])) {
|
||||
return call_user_func_array($this->methods[$methodName], $args);
|
||||
}
|
||||
|
||||
throw RunTimeException('There is no method with the given name to call');
|
||||
}
|
||||
}
|
||||
|
||||
class HackThursday {
|
||||
use MetaTrait;
|
||||
|
||||
private $dayOfWeek = 'Thursday';
|
||||
|
||||
}
|
||||
|
||||
$test = new HackThursday();
|
||||
$test->addMethod('when', function () {
|
||||
return $this->dayOfWeek;
|
||||
});
|
||||
|
||||
echo $test->when();
|
||||
```
|
||||
|
||||
php7 中增加了 `Closure::call()` 方法,可以更高效的绑定对象作用域并调用。
|
||||
|
||||
```php
|
||||
class A {private $x = 1;}
|
||||
|
||||
// Pre PHP 7 code
|
||||
$getXCB = function() {return $this->x;};
|
||||
$getX = $getXCB->bindTo(new A, 'A'); // intermediate closure
|
||||
echo $getX();
|
||||
|
||||
// PHP 7+ code
|
||||
$getX = function() {return $this->x;};
|
||||
echo $getX->call(new A);
|
||||
```
|
||||
Reference in New Issue
Block a user