zoukankan      html  css  js  c++  java
  • php 回调、匿名函数和闭包

       先来看下面2段代码,主要目的是运行各种回掉。其中Product类中有2个属性$name和$price,这里设置为公有的,以便测试。实际应用中应设置为私有的,并提供方法以便访问。

     processSale 有2个方法,registerCallback()主要负责注册回调函数,通过is_callable()函数来确保传入的值能被call_user_func()或者call_user_func_array()以及array_walk()等函数调用。   

     1 class Product
     2 {
     3     public $name;
     4     public $price;
     5     
     6     function __construct($name,$price)
     7     {
     8         $this->name = $name;
     9         $this->price = $price;
    10     }
    11 }
    12 
    13 class ProcessSale
    14 {
    15     private $callbacks;
    16 
    17     //注册回调函数
    18     function registerCallback($callbacks)
    19     {
    20         //is_callable — 检测参数是否为合法的可调用结构 
    21         if (!is_callable($callbacks)) {
    22             throw new Exception('callback not callable');
    23         }
    24         $this->callbacks[] = $callbacks;
    25     }
    26     
    27     function sale($product)
    28     {
    29         //echo "{$product->name}: processing 
    ";
    30         foreach ($this->callbacks as $callback){
    31             call_user_func($callback,$product);
    32         }
    33     }
    34 }

      写到这里,我也不是非常理解这种写法的好处。结合上面的类,简单理解就是这样可以降低业务逻辑与核心的耦合性,比如上面sale(销售)的这个方法,具体你如何销售,销售什么产品我不管,你告诉我,我帮你执行即可。

      下面创建回调来模拟过程:

      卖新商品鞋子

     1 //$logger = create_function('$product','print "logging({$product->price})";'); 蛋疼的写法
     2 
     3 //利用php 5.3以及后面的匿名函数,看着舒服多了
     4 $logger2 = function($product){
     5     print "商品 {$product->name}, 价格{$product->price}元
    ";
     6 };
     7 $processor = new ProcessSale();
     8 //注册匿名函数, 负责记录销售的信息
     9 $processor->registerCallback($logger2);
    10 //处理销售记录 ,传入你要销售产品的信息
    11 $processor->sale(new Product('shoes',6)); //商品 shoes, 价格6元

      除了上面那种方式,也可以使用对象引用和方法作为回调,如下:

      清仓甩卖

     1 class Mailer
     2 {
     3     function doMail($product)
     4     {
     5         print "清仓甩卖 {$product->name},价格{$product->price}
    ";
     6     }
     7 }
     8 $processor = new ProcessSale();
     9 $processor->registerCallback([new Mailer(),'doMail']); //is_callable 依然能检测出 此类数组。数组形式的有效回掉应该以对象作业其第一个参数,方法名第2个
    10 $processor->sale(new Product('shirt',2)); //清仓甩卖 shirt,价格2

      最后还可以使用闭包,这种新风格的匿名函数可以引用在其父作用域中的声明变量。利用user子句,让匿名函数追踪来自其父作用域的变量:

      注意有2个变量,第一个为$amt,是 warnAmount()的实参;第二个为闭包变量$count,初始化为0,注意这里需要用到引用

     1 class Totalizer{
     2     static function warnAmount($amt){
     3         //闭包
     4         $count = 0;
     5         return function($product) use ($amt, &$count){
     6             $count += $product->price;
     7             echo "count: {$count}<br/>" ;
     8             if ($count > $amt)
     9                 echo '超出预算价格 : ',($count-$amt);
    10         };
    11     }
    12 }
    13 
    14 $processor = new ProcessSale();
    15 $processor->registerCallback(Totalizer::warnAmount(40)); //设置预算价格40
    16 $processor->sale(new Product('dress',30));
    17 $processor->sale(new Product('clothes',20));

     得到结果:

       count: 30
       count: 50 
       超出预算价格 : 10

  • 相关阅读:
    Win下的批处理命令
    二分查找
    Leetcode504.Base 7七进制数
    Leetcode500.Keyboard Row键盘行
    Leetcode492.Construct the Rectangle构造矩形
    Leetcode485.Max Consecutive Ones最大连续1的个数
    Leetcode475.Heaters供暖器
    hdu1233还是畅通工程
    hdu1863畅通工程
    Leetcode459.Repeated Substring Pattern重复的子字符串
  • 原文地址:https://www.cnblogs.com/loveyouyou616/p/5499652.html
Copyright © 2011-2022 走看看