先来看下面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 \n";
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}元\n";
 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}\n";
 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

posted on 2016-05-16 21:52  睡着的糖葫芦  阅读(471)  评论(0编辑  收藏  举报