版权声明:本文为博主原创文章,未经博主允许不得转载。
PHP Closure 类是用于代表匿名函数的类,匿名函数(在 php 5.3 中被引入)会产生这个类型的对象,Closure类摘要如下:
- Closure {
- __construct ( void )
- public static Closure bind (Closure $closure , object $newthis [, mixed $newscope = 'static' ])
- public Closure bindTo (object $newthis [, mixed $newscope = 'static' ])
- }
方法说明:
Closure::__construct — 用于禁止实例化的构造函数
Closure::bind — 复制一个闭包,绑定指定的$this对象和类作用域。
Closure::bindTo — 复制当前闭包对象,绑定指定的$this对象和类作用域。
除了此处列出的方法,还有一个 __invoke 方法。这是为了与其他实现了 __invoke()魔术方法 的对象保持一致性,但调用闭包对象的过程与它无关。
下面将介绍Closure::bind和Closure::bindTo。
Closure::bind是Closure::bindTo的静态版本,其说明如下:
- public static Closure bind (Closure $closure , object $newthis [, mixed $newscope = 'static' ])
closure表示需要绑定的闭包对象。
newthis表示需要绑定到闭包对象的对象,或者NULL创建未绑定的闭包。
newscope表示想要绑定给闭包的类作用域,可以传入类名或类的示例,默认值是 'static', 表示不改变。
该方法成功时返回一个新的 Closure 对象,失败时返回FALSE。
例子说明:
- <?php
- /**
- * 复制一个闭包,绑定指定的$this对象和类作用域。
- *
- * @author 疯狂老司机
- */
- class Animal {
- private static $cat = "cat";
- private $dog = "dog";
- public $pig = "pig";
- }
-
- /*
- * 获取Animal类静态私有成员属性
- */
- $cat = static function() {
- return Animal::$cat;
- };
-
- /*
- * 获取Animal实例私有成员属性
- */
- $dog = function() {
- return $this->dog;
- };
-
- /*
- * 获取Animal实例公有成员属性
- */
- $pig = function() {
- return $this->pig;
- };
-
- $bindCat = Closure::bind($cat, null, new Animal());// 给闭包绑定了Animal实例的作用域,但未给闭包绑定$this对象
- $bindDog = Closure::bind($dog, new Animal(), 'Animal');// 给闭包绑定了Animal类的作用域,同时将Animal实例对象作为$this对象绑定给闭包
- $bindPig = Closure::bind($pig, new Animal());// 将Animal实例对象作为$this对象绑定给闭包,保留闭包原有作用域
- echo $bindCat(),'<br>';// 根据绑定规则,允许闭包通过作用域限定操作符获取Animal类静态私有成员属性
- echo $bindDog(),'<br>';// 根据绑定规则,允许闭包通过绑定的$this对象(Animal实例对象)获取Animal实例私有成员属性
- echo $bindPig(),'<br>';// 根据绑定规则,允许闭包通过绑定的$this对象获取Animal实例公有成员属性
- ?>
输出:
cat
dog
pig
Closure::bindTo — 复制当前闭包对象,绑定指定的$this对象和类作用域,其说明如下:
- public Closure Closure::bindTo (object $newthis [, mixed $newscope = 'static' ])
newthis表示绑定给闭包对象的一个对象,或者NULL来取消绑定。
newscope表示关联到闭包对象的类作用域,可以传入类名或类的示例,默认值是 'static', 表示不改变。
该方法创建并返回一个闭包对象,它与当前对象绑定了同样变量,但可以绑定不同的对象,也可以绑定新的类作用域。绑定的对象决定了返回的闭包对象中的$this的取值,类作用域决定返回的闭包对象能够调用哪些方法,也就是说,此时$this可以调用的方法,与newscope类作用域相同。
例子1:
- <?php
- function __autoload($class) {
- require_once "$class.php";
- }
-
- $template = new Template;
- $template->render(new Article, 'tpl.php');
- ?>
Template.php 模板类
- <?php
- /**
- * 模板类,用于渲染输出
- *
- * @author 疯狂老司机
- */
- class Template{
- /**
- * 渲染方法
- *
- * @access public
- * @param obj 信息类
- * @param string 模板文件名
- */
- public function render($context, $tpl){
- $closure = function($tpl){
- ob_start();
- include $tpl;
- return ob_end_flush();
- };
- $closure = $closure->bindTo($context, $context);
- $closure($tpl);
- }
-
- }
Article.php 信息类
- <?php
- /**
- * 文章信息类
- *
- * @author 疯狂老司机
- */
- class Article{
- private $title = "这是文章标题";
- private $content = "这是文章内容";
- }
tpl.php 模板文件
- <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
- <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
- <head>
- <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
- </head>
- <body>
- <h1><?php echo $this->title;?></h1>
- <p><?php echo $this->content;?></p>
- </body>
- </html>
运行时确保以上文件位于同级目录。
输出:
这是文章标题
这是文章内容
例子2:
- <?php
- /**
- * 给类动态添加新方法
- *
- * @author 疯狂老司机
- */
- trait DynamicTrait {
-
- /**
- * 自动调用类中存在的方法
- */
- public function __call($name, $args) {
- if(is_callable($this->$name)){
- return call_user_func($this->$name, $args);
- }else{
- throw new \RuntimeException("Method {$name} does not exist");
- }
- }
- /**
- * 添加方法
- */
- public function __set($name, $value) {
- $this->$name = is_callable($value)?
- $value->bindTo($this, $this):
- $value;
- }
- }
-
- /**
- * 只带属性不带方法动物类
- *
- * @author 疯狂老司机
- */
- class Animal {
- use DynamicTrait;
- private $dog = 'dog';
- }
-
- $animal = new Animal;
-
- // 往动物类实例中添加一个方法获取实例的私有属性$dog
- $animal->getdog = function() {
- return $this->dog;
- };
-
- echo $animal->getdog();
-
- ?>
输出:
dog
例子3:
- <?php
- /**
- * 一个基本的购物车,包括一些已经添加的商品和每种商品的数量
- *
- * @author 疯狂老司机
- */
- class Cart {
- // 定义商品价格
- const PRICE_BUTTER = 1.00;
- const PRICE_MILK = 3.33;
- const PRICE_EGGS = 8.88;
-
- protected $products = array();
-
- /**
- * 添加商品和数量
- *
- * @access public
- * @param string 商品名称
- * @param string 商品数量
- */
- public function add($item, $quantity) {
- $this->products[$item] = $quantity;
- }
-
- /**
- * 获取单项商品数量
- *
- * @access public
- * @param string 商品名称
- */
- public function getQuantity($item) {
- return isset($this->products[$item]) ? $this->products[$item] : FALSE;
- }
-
- /**
- * 获取总价
- *
- * @access public
- * @param string 税率
- */
- public function getTotal($tax) {
- $total = 0.00;
-
- $callback = function ($quantity, $item) use ($tax, &$total) {
- $pricePerItem = constant(__CLASS__ . "::PRICE_" . strtoupper($item));
- $total += ($pricePerItem * $quantity) * ($tax + 1.0);
- };
-
- array_walk($this->products, $callback);
- return round($total, 2);;
- }
- }
-
- $my_cart = new Cart;
-
- // 往购物车里添加商品及对应数量
- $my_cart->add('butter', 10);
- $my_cart->add('milk', 3);
- $my_cart->add('eggs', 12);
-
- // 打出出总价格,其中有 5% 的销售税.
- echo $my_cart->getTotal(0.05);
-
- ?>
输出:
132.88
补充说明:闭包可以使用USE关键连接外部变量。
总结:合理使用闭包能使代码更加简洁和精炼。
转载自:http://blog.csdn.net/wuxing26jiayou/article/details/51067190