PHP Closure类详解

PHP Closure 类是用于代表匿名函数的类,匿名函数(在 PHP 5.3 中被引入)会产生这个类型的对象,Closure类摘要如下:

  1. Closure {  
  2.     __construct ( void )  
  3.     public static Closure bind (Closure $closure , object $newthis [, mixed $newscope = 'static' ])  
  4.     public Closure bindTo (object $newthis [, mixed $newscope = 'static' ])  
  5. }  
方法说明:

Closure::__construct — 用于禁止实例化的构造函数
Closure::bind — 复制一个闭包,绑定指定的$this对象和类作用域。
Closure::bindTo — 复制当前闭包对象,绑定指定的$this对象和类作用域。

除了此处列出的方法,还有一个 __invoke 方法。这是为了与其他实现了 __invoke()魔术方法 的对象保持一致性,但调用闭包对象的过程与它无关。

下面将介绍Closure::bindClosure::bindTo

Closure::bind是Closure::bindTo的静态版本,其说明如下:

  1. public static Closure bind (Closure $closure , object $newthis [, mixed $newscope = 'static' ])  

closure表示需要绑定的闭包对象。
newthis表示需要绑定到闭包对象的对象,或者NULL创建未绑定的闭包。
newscope表示想要绑定给闭包的类作用域,可以传入类名或类的示例,默认值是 'static', 表示不改变。

该方法成功时返回一个新的 Closure 对象,失败时返回FALSE。

例子说明:

  1. <?php  
  2. /**  
  3.  * 复制一个闭包,绑定指定的$this对象和类作用域。  
  4.  *  
  5.  * @author 疯狂老司机  
  6.  */  
  7. class Animal {  
  8.     private static $cat = "cat";  
  9.     private $dog = "dog";  
  10.     public $pig = "pig";  
  11. }  
  12.   
  13. /*  
  14.  * 获取Animal类静态私有成员属性 
  15.  */  
  16. $cat = static function() {  
  17.     return Animal::$cat;  
  18. };  
  19.   
  20. /*  
  21.  * 获取Animal实例私有成员属性 
  22.  */  
  23. $dog = function() {  
  24.     return $this->dog;  
  25. };  
  26.   
  27. /*  
  28.  * 获取Animal实例公有成员属性 
  29.  */  
  30. $pig = function() {  
  31.     return $this->pig;  
  32. };  
  33.   
  34. $bindCat = Closure::bind($cat, null, new Animal());// 给闭包绑定了Animal实例的作用域,但未给闭包绑定$this对象  
  35. $bindDog = Closure::bind($dognew Animal(), 'Animal');// 给闭包绑定了Animal类的作用域,同时将Animal实例对象作为$this对象绑定给闭包  
  36. $bindPig = Closure::bind($pignew Animal());// 将Animal实例对象作为$this对象绑定给闭包,保留闭包原有作用域  
  37. echo $bindCat(),'<br>';// 根据绑定规则,允许闭包通过作用域限定操作符获取Animal类静态私有成员属性  
  38. echo $bindDog(),'<br>';// 根据绑定规则,允许闭包通过绑定的$this对象(Animal实例对象)获取Animal实例私有成员属性  
  39. echo $bindPig(),'<br>';// 根据绑定规则,允许闭包通过绑定的$this对象获取Animal实例公有成员属性  
  40. ?>  

输出:

cat
dog
pig

Closure::bindTo — 复制当前闭包对象,绑定指定的$this对象和类作用域,其说明如下:

  1. public Closure Closure::bindTo (object $newthis [, mixed $newscope = 'static' ])  
newthis表示绑定给闭包对象的一个对象,或者NULL来取消绑定。
newscope表示关联到闭包对象的类作用域,可以传入类名或类的示例,默认值是 'static', 表示不改变。

该方法创建并返回一个闭包对象,它与当前对象绑定了同样变量,但可以绑定不同的对象,也可以绑定新的类作用域。绑定的对象决定了返回的闭包对象中的$this的取值,类作用域决定返回的闭包对象能够调用哪些方法,也就是说,此时$this可以调用的方法,与newscope类作用域相同。

例子1:

  1. <?php  
  2. function __autoload($class) {  
  3.     require_once "$class.php";  
  4. }  
  5.   
  6. $template = new Template;  
  7. $template->render(new Article, 'tpl.php');  
  8. ?>  


Template.php 模板类

  1. <?php  
  2. /**  
  3.  * 模板类,用于渲染输出  
  4.  *  
  5.  * @author 疯狂老司机  
  6.  */  
  7. class Template{  
  8.     /** 
  9.      * 渲染方法 
  10.      * 
  11.      * @access public  
  12.      * @param obj 信息类 
  13.      * @param string 模板文件名 
  14.      */  
  15.     public function render($context$tpl){  
  16.         $closure = function($tpl){  
  17.             ob_start();  
  18.             include $tpl;  
  19.             return ob_end_flush();  
  20.         };  
  21.         $closure = $closure->bindTo($context$context);  
  22.         $closure($tpl);  
  23.     }  
  24.   
  25. }  

Article.php 信息类
  1. <?php  
  2. /**  
  3.  * 文章信息类  
  4.  *  
  5.  * @author 疯狂老司机  
  6.  */  
  7. class Article{  
  8.     private $title = "这是文章标题";  
  9.     private $content = "这是文章内容";  
  10. }  


tpl.php 模板文件
  1. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">  
  2. <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">  
  3.     <head>  
  4.         <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">  
  5.     </head>  
  6.     <body>  
  7.         <h1><?php echo $this->title;?></h1>  
  8.         <p><?php echo $this->content;?></p>  
  9.     </body>  
  10. </html>  
运行时确保以上文件位于同级目录。

输出:

这是文章标题

这是文章内容


例子2:
  1. <?php  
  2. /**  
  3.  * 给类动态添加新方法 
  4.  *  
  5.  * @author 疯狂老司机 
  6.  */  
  7. trait DynamicTrait {  
  8.   
  9.     /** 
  10.      * 自动调用类中存在的方法 
  11.      */  
  12.     public function __call($name$args) {  
  13.         if(is_callable($this->$name)){  
  14.             return call_user_func($this->$name$args);  
  15.         }else{  
  16.             throw new \RuntimeException("Method {$name} does not exist");  
  17.         }  
  18.     }  
  19.     /** 
  20.      * 添加方法 
  21.      */  
  22.     public function __set($name$value) {  
  23.         $this->$name = is_callable($value)?   
  24.             $value->bindTo($this$this):   
  25.             $value;  
  26.     }  
  27. }  
  28.   
  29. /**  
  30.  * 只带属性不带方法动物类 
  31.  *  
  32.  * @author 疯狂老司机 
  33.  */  
  34. class Animal {  
  35.     use DynamicTrait;  
  36.     private $dog = 'dog';  
  37. }  
  38.   
  39. $animal = new Animal;  
  40.   
  41. // 往动物类实例中添加一个方法获取实例的私有属性$dog  
  42. $animal->getdog = function() {  
  43.     return $this->dog;  
  44. };  
  45.   
  46. echo $animal->getdog();  
  47.   
  48. ?>  
输出:

dog

例子3:

  1. <?php  
  2. /**  
  3.  * 一个基本的购物车,包括一些已经添加的商品和每种商品的数量 
  4.  *  
  5.  * @author 疯狂老司机 
  6.  */  
  7. class Cart {  
  8.     // 定义商品价格  
  9.     const PRICE_BUTTER  = 1.00;  
  10.     const PRICE_MILK    = 3.33;  
  11.     const PRICE_EGGS    = 8.88;  
  12.    
  13.     protected   $products = array();  
  14.   
  15.     /** 
  16.      * 添加商品和数量 
  17.      * 
  18.      * @access public  
  19.      * @param string 商品名称 
  20.      * @param string 商品数量 
  21.      */  
  22.     public function add($item$quantity) {  
  23.         $this->products[$item] = $quantity;  
  24.     }  
  25.   
  26.     /** 
  27.      * 获取单项商品数量 
  28.      * 
  29.      * @access public  
  30.      * @param string 商品名称 
  31.      */  
  32.     public function getQuantity($item) {  
  33.         return isset($this->products[$item]) ? $this->products[$item] : FALSE;  
  34.     }  
  35.   
  36.     /** 
  37.      * 获取总价 
  38.      * 
  39.      * @access public  
  40.      * @param string 税率 
  41.      */  
  42.     public function getTotal($tax) {  
  43.         $total = 0.00;  
  44.   
  45.         $callback = function ($quantity$itemuse ($tax, &$total) {  
  46.             $pricePerItem = constant(__CLASS__ . "::PRICE_" . strtoupper($item));  
  47.             $total += ($pricePerItem * $quantity) * ($tax + 1.0);  
  48.         };  
  49.            
  50.         array_walk($this->products, $callback);  
  51.         return round($total, 2);;  
  52.     }  
  53. }  
  54.   
  55. $my_cart = new Cart;  
  56.   
  57. // 往购物车里添加商品及对应数量  
  58. $my_cart->add('butter', 10);  
  59. $my_cart->add('milk', 3);  
  60. $my_cart->add('eggs', 12);  
  61.   
  62. // 打出出总价格,其中有 5% 的销售税.  
  63. echo $my_cart->getTotal(0.05);  
  64.   
  65. ?>  
输出:

132.88

补充说明:闭包可以使用USE关键连接外部变量。

总结:合理使用闭包能使代码更加简洁和精炼。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值