0%

PHP中匿名函数和闭包初探

「闭包」和「匿名」的区别

首先,虽然闭包和匿名在PHP中对应的都是一个东西,但是闭包和匿名并不等价。

匿名是指这个函数可以想变量一样操作,例如可以赋值给一个变量或者作为参数传递,作为函数的返回值等。

闭包则是指这个函数可以从上下文中捕获变量(不是通过传参获取),例如PHP使用use这个子句来完成这个操作;

实际上,闭包和匿名函数是伪装成函数的对象。他们是Closure类的实例。
闭包和字符串、整数一样,是一等值类型

使用举例

提到闭包就不得不想起匿名函数,也叫闭包函数(closures),貌似PHP闭包实现主要就是靠它.所以,在PHP中闭包(Closure)就是匿名函数;

声明一个匿名函数

1
2
$func = function(){
};

可以看到,匿名函数因为没有名字,如果要使用它,需要将其返回给一个变量。匿名函数也像普通函数一样可以声明参数,调用方法也相同:

1
2
3
4
5
6
7
$message = function($name)
{
echo 'hello '.$name;
};

$message('world');
//输出hello world

通常会把闭包当做函数的回调来使用

我们之所以能调用$message变量,是因为这个变量的值是一个闭包,而且闭包对象实现了__invoke()魔术方法。只要变量名后有(),PHP就会查找并调用__invoke()方法。

array_map(), preg_replace_callback()方法都会用到回调函数,这是使用闭包的最佳时机!

1
2
3
4
5
$numbersPlusOne = array_map(function ($number) {
return $number + 1;
}, [1, 2, 3]);
print_r($numbersPlusOne);
//输出[2, 3, 4]

use关键字

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
<?php
// 一个基本的购物车,包括一些已经添加的商品和每种商品的数量。
// 其中有一个方法用来计算购物车中所有商品的总价格。该方法使用了一个closure作为回调函数。
class Cart
{
const PRICE_BUTTER = 1.00;
const PRICE_MILK = 3.00;
const PRICE_EGGS = 6.95;

protected $products = array();

public function add($product, $quantity)
{
$this->products[$product] = $quantity;
}

public function getQuantity($product)
{
return isset($this->products[$product]) ? $this->products[$product] :
FALSE;
}

public function getTotal($tax)
{
$total = 0.00;

$callback =
function ($quantity, $product) use ($tax, &$total)
{
$pricePerItem = constant(__CLASS__ . "::PRICE_" .
strtoupper($product));
$total += ($pricePerItem * $quantity) * ($tax + 1.0);
};

array_walk($this->products, $callback);
return round($total, 2);;
}
}

$my_cart = new Cart;

// 往购物车里添加条目
$my_cart->add('butter', 1);
$my_cart->add('milk', 3);
$my_cart->add('eggs', 6);

// 打出出总价格,其中有 5% 的销售税.
print $my_cart->getTotal(0.05) . "\n";
// The result is 54.29
?>

匿名函数不会自动从父作用域中继承变量,注意从父作用域继承变量和使用全局变量是不同的。

如果父作用域本身就是全局的 情况下就不存在从父作用域继承变量了,如果不是全局的话,想要使用父作用域中的变量,必须在声明匿名函数时候使用use换键字 来定义继承父作用域的变量。