先来看下面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