匿名函数
匿名函数(Anonymous functions),也叫闭包函数(closures),允许 临时创建一个没有指定名称的函数。最经常用作回调函数(callback)参数的值。当然,也有其它应用的情况。
闭包的语法很简单,需要注意的关键字就只有use,use意思是连接闭包和外界变量。
<?php$a = function() use($b) {}
Example #1 匿名函数示例
echo preg_replace_callback('~-([a-z])~', function ($match) {return strtoupper($match[1]);}, 'hello-world');// 输出 helloWorld
闭包函数也可以作为变量的值来使用。PHP 会自动把此种表达式转换成内置类 Closure 的对象实例。把一个 closure 对象赋值给一个变量的方式与普通变量赋值的语法是一样的,最后也要加上分号:
Example #2 匿名函数变量赋值示例
<?php$greet = function($name){printf("Hello %s\r\n", $name);};$greet('World');$greet('PHP');
减少函数的参数
Example #3 匿名函数变量赋值示例
<?phpfunction html ($code, $inner, $id="", $class=""){if ($id !== "") $id = " id = \"$id\"" ;$class = ($class !== "")? " class =\"$class\"":">";$open = "<$code$id$class";$close = "</$code>";$tag = function ($inner = "") use ($open, $close){return "$open$inner$close";};return $tag($inner);}echo html('i', '这是加粗');
减少foreach的循环的代码
Closure 对象也会从父作用域中继承类属性。这些变量都必须在函数或类的头部声明。从父作用域中继承变量与使用全局变量是不同的。全局变量存在于一个全局的范围,无论当前在执行的是哪个函数。而 closure 的父作用域则是声明该 closure 的函数(不一定要是它被调用的函数)。示例如下:
Example #4 Closures 和作用域
<?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";// 最后结果是 54.29?>
匿名函数目前是通过 Closure 类来实现的。
解除递归函数
<?php$fib = function($n) use(&$fib) {if($n == 0 || $n == 1) return 1;return $fib($n - 1) + $fib($n - 2);};echo $fib(2) . "\n"; // 2$lie = $fib;$fib = function(){die('error');};//rewrite $fib variableecho $lie(5); // error because $fib is referenced by closure
注意上题中的use使用了&,这里不使用&会出现错误fib(
n-1)是找不到function的(前面没有定义fib的类型)
所以想使用闭包解除循环函数的时候就需要使用这样的形式:
<?php$recursive = function () use (&$recursive){// The function is now available as $recursive}
关于延迟绑定
如果你需要延迟绑定use里面的变量,你就需要使用引用,否则在定义的时候就会做一份拷贝放到use中
<?php$result = 0;$one = function(){ var_dump($result); };$two = function() use ($result){ var_dump($result); };$three = function() use (&$result){ var_dump($result); };$result++;$one(); // outputs NULL: $result is not in scope$two(); // outputs int(0): $result was copied$three(); // outputs int(1)
使用引用和不使用引用就代表了是调用时赋值,还是申明时候赋值
更新日志
版本 说明
5.4.0 $this 可用于匿名函数。
5.3.0 可以使用匿名函数。
注释
Note: 可以在 closure 中使用 func_num_args(), func_get_arg() 和 func_get_args()。
参考:http://www.cnblogs.com/yjf512/archive/2012/10/29/2744702.html