PHP

PHP中Closure::bind()的理解

有如下匿名函数:

$fun = function(){
        return $this->name;
}

或者

$fun = function(){
        return A::$height;
}

echo $fun();//会报错的

其实单独这段代码是肯定不能运行 调用的,因为里面有个$this,程序压根不知道你这个$this是代表那个对象 或 那个类(并且就算知道那个对象或类,该对象是否拥有name属性,如果没有照样会有问题)

因此想让其正常运行肯定有前提条件啊(就好比你想遍历某个数组一样,如果这个数组压根你就没提前定义 声明 肯定会报错的)
如果这样:

<?php
class A{

    private $name = '王力宏';
    protected $age = '30';
    private static $weight = '70kg';
    public $address = '中国';
    public static $height = '180cm';

}

$fun = function(){
    return $this->name;
} ;
$cf = Closure::bind($fun,new A() ,'A');   //该函数返回一个新的 Closure 对象 或者在失败时返回 FALSE

echo $cf();//输出 王力宏  为什么呢:bind第一个参数是匿名函数,第二个A实例对象,第三个代表作用域
//网上很多讲解是说把匿名函数绑定到了实例对象上了  然后就怎么着......很多新手看了依然一脸懵逼。其实是匿名函数里的$this被指定到了或绑定到了A实例对象上了

Closure::bind($fun,new A() );这个使用 你可以理解成对匿名函数做了如下过程:
$fun = function(){
     $this = new A();//你可以想象认为,$this就成了A类的实例对象了,然后在去访问name属性,就和我们正常实例化类访问成员属性一样,上面2中的例子$obj = new A()就是这样,(因为$this是关键字,在这里我们其实不能直接$this = new A();这么写,为了好理解我写成$this,但是原理还是这个意思),但是我们都知道因为name属性是私有的,上面2中我已说过,实例对象不能访问私有属性,那该怎么办呢,于是添加第三个参数就很重要了,一般传入传入一个对应对象,或对应类名(对应的意思是:匿名函数中$this-name想获取name属性值,你这个$this想和那个类和对象绑定在一起呢,就是第二个参数,这时你第三个参数写和第二个参数写一样的对象或类就行了,就是作用域为这个对象或类,这就会让原理的name私有属性变为公有属性)
    return $this->name;
} ;

为了加深理解我在举两个例子:

<?php

class A{
    private $name = '王力宏';
    protected $age = '30';
    private static $weight = '70kg';
    public $address = '中国';
    public static $height = '180cm';

}

$fun = function(){
    $obj = new A();
    return $obj->address;
};

echo $fun();//正常 输出 中国 ,该例子其实在上面2中已经讲过了 如果跟这个还不能理解 就不要往下看了 好好补一下基础

$fun2 = function(){
    return $this->address;
};
//echo $fun2();这样运行会报错  所以我们要进行匿名函数的绑定  是匿名函数里的$this有所指,**必要时还要改变要访问属性的作用域**

$newfun2 = Closure::bind($fun2, new A() );//使用了该函数后 ,该函数返回一个全新的匿名的函数,和原来匿名函数$fun2一模一样,只是其中 $this被指向了A实例对象,这样就能访问address属性了

echo $newfun2();//正常 输出 中国,在这里数一下bind这次为什么没添加第三个参数,因为我们要访问的address属性是公有的,一个对象实例是可以直接访问公有属性的,这个例子中只要匿名函数中$this被指向了A对象实例(或者叫绑定也可以),就能访问到公有属性,所以可以不用添加第三个参数,当然你加上了第三个参数 如这样Closure::bind($fun2, new A(), ‘A’ );或Closure::bind($fun2, new A(), nwe A() );不影响 照样运行,就好比把原来公有属性 变为公有属性 不影响的(一般当我们访问的属性为私有属性时,才使用第三个参数改变作用域 ,使其变为公有属性)

下面来看最后一例子,再次加深一下理解:

<?php
class A{
    private $name = '王力宏';
    protected $age = '30';
    private static $weight = '70kg';
    public $address = '中国';
    public static $height = '180cm';

}
$fun = function(){
    return A::$weight;
};
//echo $fun();   运行会报错 因为weight为私有属性  上面2中例子访问height属性是可以的,height为公有属性,所以把weight改成height是可以正常运行的,但是我们现在就想访问这个私有静态属性,我们该怎么办,于是Closure::bind出场了
$newfun = Closure::bind($fun,null,'A');//通过bind函数作用,返回一个和$fun匿名函数一模一样的匿名函数,只是该匿名函数中A::$weight,       weight属性由私有变成公有属性了。
echo $newfun();// 正常 输出 70kg  ,为什么第二个参数又成null了呢,因为在该匿名函数中A::$weight 这属于正常类使用啊(php中  类名::公有静态属性,这是正常访问方法,上面2中例子已经说的很清楚了),所以不用绑定到某个对象上去了,于是第二个参数可以省略,唯一遗憾的是weight属性虽是静态属性,但是其权限是private私有属性,于是我们要把私有属性变公有属性就可以了,这时把第三个参数加上去就可以了,第三个参数可以是A类(Closure::bind($fun,null,'A')),也可以是A类的对象实例(Closure::bind($fun,null, new A() )),两种写法都可以,最终第三个参数的添加使私有属性变成了公有属性,(这个例子中当然你非得添加第二个参数肯定也没问题,只要第二个参数是A的实例对象就行Closure::bind($fun,new A(),'A'),不影响,只是说  A::$weight 这种使用方法本身就是正常使用,程序本身就知道你用的是A类,你在去把它指向到A类自己的对象实例上,属于多此一举,因此第二个参数加不加都行,不加写null就行)

综上大家应该理解其用法了吧,有时第二个参数为null,有时第三个参数可以不要,这些都跟你匿名函数里 代码中访问的方式紧密相关

总结:

1、一般匿名函数中有$this->name类似这样用 $this访问属性方式时,你在使用bind绑定时 ,第二个参数肯定要写,写出你绑定那个对象实例,第三个参数要不要呢,要看你访问的这个属性,在绑定对象中的权限属性,如果是privateprotected 你要使用第三个参数 使其变为公有属性, 如果本来就是公有,你可以省略,也可以不省略
2、一般匿名函数中是 类名::静态属性 类似这样的访问方式(比如例子中A::$weight),你在使用bind绑定时,第二个参数可以写null,也可以写出具体的对象实例,一般写null就行(写了具体对象实例多此一举),第三个参数写不写还是得看你访问的这个静态属性的权限是 private 还是 public,如果是私有private或受保护protected的,你就得第三个参数必须写,才能使其权限变为公有属性 正常访问,如果本来就是公有public可以不用写,可以省略

转载自:
https://blog.csdn.net/qq_27718961/article/details/91043221

1 条评论

  1. dwf
    dwf

    学到了

发表评论

电子邮件地址不会被公开。 必填项已用*标注

相关推荐