匿名函数

匿名函数(Anonymous functions),也叫闭包函数(closures),允许 临时创建一个没有指定名称的函数。最经常用作回调函数(callback)参数的值。当然,也有其它应用的情况。
闭包的语法很简单,需要注意的关键字就只有use,use意思是连接闭包和外界变量。

  1. <?php
  2. $a = function() use($b) {}

Example #1 匿名函数示例

  1. echo preg_replace_callback('~-([a-z])~', function ($match) {
  2. return strtoupper($match[1]);
  3. }, 'hello-world');
  4. // 输出 helloWorld

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

Example #2 匿名函数变量赋值示例

  1. <?php
  2. $greet = function($name)
  3. {
  4. printf("Hello %s\r\n", $name);
  5. };
  6. $greet('World');
  7. $greet('PHP');

减少函数的参数

Example #3 匿名函数变量赋值示例

  1. <?php
  2. function html ($code, $inner, $id="", $class=""){
  3. if ($id !== "") $id = " id = \"$id\"" ;
  4. $class = ($class !== "")? " class =\"$class\"":">";
  5. $open = "<$code$id$class";
  6. $close = "</$code>";
  7. $tag = function ($inner = "") use ($open, $close){
  8. return "$open$inner$close";
  9. };
  10. return $tag($inner);
  11. }
  12. echo html('i', '这是加粗');

减少foreach的循环的代码

Closure 对象也会从父作用域中继承类属性。这些变量都必须在函数或类的头部声明。从父作用域中继承变量与使用全局变量是不同的。全局变量存在于一个全局的范围,无论当前在执行的是哪个函数。而 closure 的父作用域则是声明该 closure 的函数(不一定要是它被调用的函数)。示例如下:

Example #4 Closures 和作用域

  1. <?php
  2. // 一个基本的购物车,包括一些已经添加的商品和每种商品的数量。
  3. // 其中有一个方法用来计算购物车中所有商品的总价格,该方法使
  4. // 用了一个 closure 作为回调函数。
  5. class Cart
  6. {
  7. const PRICE_BUTTER = 1.00;
  8. const PRICE_MILK = 3.00;
  9. const PRICE_EGGS = 6.95;
  10. protected $products = array();
  11. public function add($product, $quantity)
  12. {
  13. $this->products[$product] = $quantity;
  14. }
  15. public function getQuantity($product)
  16. {
  17. return isset($this->products[$product]) ? $this->products[$product] :
  18. FALSE;
  19. }
  20. public function getTotal($tax)
  21. {
  22. $total = 0.00;
  23. $callback =
  24. function ($quantity, $product) use ($tax, &$total)
  25. {
  26. $pricePerItem = constant(__CLASS__ . "::PRICE_" .
  27. strtoupper($product));
  28. $total += ($pricePerItem * $quantity) * ($tax + 1.0);
  29. };
  30. array_walk($this->products, $callback);
  31. return round($total, 2);;
  32. }
  33. }
  34. $my_cart = new Cart;
  35. // 往购物车里添加条目
  36. $my_cart->add('butter', 1);
  37. $my_cart->add('milk', 3);
  38. $my_cart->add('eggs', 6);
  39. // 打出出总价格,其中有 5% 的销售税.
  40. print $my_cart->getTotal(0.05) . "\n";
  41. // 最后结果是 54.29
  42. ?>

匿名函数目前是通过 Closure 类来实现的。

解除递归函数

  1. <?php
  2. $fib = function($n) use(&$fib) {
  3. if($n == 0 || $n == 1) return 1;
  4. return $fib($n - 1) + $fib($n - 2);
  5. };
  6. echo $fib(2) . "\n"; // 2
  7. $lie = $fib;
  8. $fib = function(){die('error');};//rewrite $fib variable
  9. echo $lie(5); // error because $fib is referenced by closure

注意上题中的use使用了&,这里不使用&会出现错误fib(

n-1)是找不到function的(前面没有定义fib的类型)

所以想使用闭包解除循环函数的时候就需要使用这样的形式:

  1. <?php
  2. $recursive = function () use (&$recursive){
  3. // The function is now available as $recursive
  4. }

关于延迟绑定

如果你需要延迟绑定use里面的变量,你就需要使用引用,否则在定义的时候就会做一份拷贝放到use中

  1. <?php
  2. $result = 0;
  3. $one = function()
  4. { var_dump($result); };
  5. $two = function() use ($result)
  6. { var_dump($result); };
  7. $three = function() use (&$result)
  8. { var_dump($result); };
  9. $result++;
  10. $one(); // outputs NULL: $result is not in scope
  11. $two(); // outputs int(0): $result was copied
  12. $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

分类: web

标签:   php