「闭包」和「匿名」的区别
首先,虽然闭包和匿名在PHP中对应的都是一个东西,但是闭包和匿名并不等价。
匿名是指这个函数可以想变量一样操作,例如可以赋值给一个变量或者作为参数传递,作为函数的返回值等。
闭包则是指这个函数可以从上下文中捕获变量(不是通过传参获取),例如PHP使用use这个子句来完成这个操作;
实际上,闭包和匿名函数是伪装成函数的对象。他们是Closure类的实例。
闭包和字符串、整数一样,是一等值类型
使用举例
提到闭包就不得不想起匿名函数,也叫闭包函数(closures),貌似PHP闭包实现主要就是靠它.所以,在PHP中闭包(Closure)就是匿名函数;
声明一个匿名函数
可以看到,匿名函数因为没有名字,如果要使用它,需要将其返回给一个变量。匿名函数也像普通函数一样可以声明参数,调用方法也相同:
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换键字 来定义继承父作用域的变量。