对于闭包(也叫匿名)的理解,只要记住一点就可以了:匿名是没有明确的名字进行定义的。
匿名函数
声明的格式如下:
$func = function(){ };//带结束符
也可以带上形参,如下
$func = function($data){ echo $data; };
实现闭包
可以在普通函数中,将一个匿名函数当做参数传入,也可以被返回,这就实现了一个闭包。
函数中调用一个匿名函数,如下
<?php function get_param(){ $func = function($str){ echo $str; }; $func("This is test"); } get_param(); /** *输出: *This is test */ ?>
函数中调用一个匿名函数,并返回它,如下
<?php function get_param(){ $func = function($str){ echo $str; }; return $func; } $func = get_param(); $func('hello world'); /** *输出: *hello world */ ?>
将匿名函数当做参数传入到函数中,并调用它,如下
function get_param($call_back_func){ $call_back_func(); } $func = function(){ echo "hello"; }; get_param($func); /** *输出: *hello */
直接将匿名函数当做参数传入,如下
<?php function get_param($call_back_func){ $call_back_func(); } get_param(function(){ echo "str"; }); /** *输出: *str */ ?>
闭包关键字:use
闭包能保存所在代码块的变量和值。闭包可以使用use关键字来调用所在代码块的上下文变量和值。
如下:
<?php function get_param(){ $str = 'fu'; $func = function() use($str){ echo $str; }; $func("This is test"); } get_param(); /** *输出: *fu */ ?>
使用引用改变变量和值,可以使用&进行改变,如下:
<?php function get_param(){ $str = 'fu'; $func = function() use(&$str){ $str = "hello"; }; echo $str; $func("This is test"); echo $str; } get_param(); /** *输出: *fu */ ?>
Closure类
Closure类,也就是闭包类,php中,闭包都是Closure类的实例
可以测试看看
<?php $func = function(){ }; var_dump($func instanceof Closure); //输出bool(true) ?>
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对象和类作用域。
Closure::bind
closure 表示需要绑定的闭包对象。
newthis 表示需要绑定到闭包对象的对象,或者NULL创建未绑定的闭包。
newscope 想要绑定给闭包的类作用域,或者 ‘static’ 表示不改变。如果传入一个对象,则使用这个对象的类型名。 类作用域用来决定在闭包中 $this 对象的 私有、保护方法 的可见性。
总结,当访问的闭包$this对象是私有、保护、公有时, newthis 需要传入 需要绑定的对象或者null,当访问的是静态属性或方法时,必须传入null,如下测试:
<?php class Animal{ private static $cat = 'cat'; private $dog = 'dog'; protected $row = 'row'; public $pig = 'pig'; public function say(){ echo "hello"; } } $cat = function(){ return Animal::$cat; }; $dog = function(){ return $this->dog; }; $row = function(){ return $this->row; }; $pig = function(){ return $this->pig; }; $say = function(){ return $this->say(); }; $bindCat = Closure::bind($cat,null,new Animal()); echo $bindCat();echo " "; $bindCat = Closure::bind($cat,new Animal(),new Animal()); echo $bindCat();echo " "; $bindCat = Closure::bind($cat,new Animal(),'Animal'); echo $bindCat();echo " "; $bindCat = Closure::bind($cat,null,'Animal'); echo $bindCat();echo " "; echo "<br/>"; $bindDog = Closure::bind($dog,new Animal(),'Animal'); echo $bindDog(); echo "<br/>"; $bindRow = Closure::bind($row,new Animal(),'Animal'); echo $bindRow(); echo "<br/>"; $say = Closure::bind($say,new Animal(),'Animal'); echo $say(); ?>
Closure::bindTo
newthis 表示需要绑定到闭包对象的对象,或者NULL创建未绑定的闭包。
newscope 想要绑定给闭包的类作用域,或者 ‘static’ 表示不改变。如果传入一个对象,则使用这个对象的类型名。 类作用域用来决定在闭包中 $this 对象的 私有、保护方法 的可见性。
如下两个实例所示
实例1:
<?php class A { function __construct($val) { $this->val = $val; } function getClosure() { //returns closure bound to this object and scope return function() { return $this->val; }; } } $ob1 = new A(1); $ob2 = new A(2); $fun = function(){ return $this->val; }; $cl = $ob1->getClosure(); echo $cl()."<br/>"; $cl = $cl->bindTo($ob2); echo $cl()."<br/>"; $cl = $fun->bindTo($ob2,'A'); echo $cl()."<br/>"; ?>
实例2:
class A { public static $val=1; function getClosure() { //returns closure bound to this object and scope return function() { return self::$val; }; } } $fun = function(){ return A::$val; }; $cl = $fun->bindTo(null,'A'); echo $cl()."<br/>";