与public属性绑定
namespace php\demo\part1;
//空行
//首先定义一个用来演示的类
class Youth
{
public $name;
public function show(){
//非静态成员是通过this关键字和->结合来访问
return $this->name.'是一名年轻人';
}
}
//定义一个匿名函数,这个函数用来绑定youth类中的属性,用于设置类中属性的值,该函数接收1个$name参数
$setValueFun = function ($name){
//因为这个函数将要和类绑定,绑定后就像类中的一个方法,因此在代码中要用$this->name来访问类中的属性
$this->name = $name;
};
//将Youth类实例出一个对象
$obj = new Youth();
//bind()是Closure类中的一个静态方法,其返回值是上面那个匿名函数的复制。
//该方法第一个参数代表要准备和类绑定的匿名函数,也就是上面$setvalue代表的匿名函数。
//该方法第二参数代表要绑定的类的一个实例
//该方法第三个参数代表类作用域,在使用的时候就是用绑定类的类名,因为这段代码只是设置public属性,因此可以省略。
//下面代码中在Closure前面加上'\'是使用的完全限定名称,代表全局命名空间,也可以用use Closure来代替
$newSetValueFun = \Closure::bind($setValueFun,$obj);
//还可以直接这么写,省略掉上面实例化的步骤
//$newSetValueFun = Closure::bind($setValueFun,new Youth());
//通过$newSetValueFun来给实例化出来的对象中的public属性$name赋值
$newSetValueFun('Lucy');
//调用Youth类中的show方法来验证
echo $obj->show();
//经验证最后输出:Lucy是一名年轻人
与private属性绑定(protected属性操作相同)
//命名空间
namespace php\demo\part1;
use Closure;
//空行
//首先定义一个用来演示的类
class Youth
{
private $weight;
public function __toString(){
//非静态成员是通过this关键字和->结合来访问,因此public和private属性访问方法相同
return '一名年轻人的体重是'.$this->weight.'KG';
}
}
//定义一个匿名函数,这个函数用来绑定youth类中的属性,用于设置类中属性的值,该函数接收2个参数
$setValueFun = function ($weight){
//因为这个函数将要和类绑定,绑定后就像类中已经定义的一个方法一样,因此在代码中要用$this->name来访问类中的属性
$this->weight = $weight;
};
//将Youth类实例出一个对象
$obj = new Youth();
//bind()是Closure类中的一个静态方法,其返回值是上面那个匿名函数的复制。
//该方法第一个参数代表要准备和类绑定的匿名函数,也就是上面$setvalue代表的匿名函数。
//该方法第二参数代表要绑定的类的一个实例,换个角度看就是说匿名函数中的this代表哪个实例化的对象。
//该方法第三个参数代表类作用域,在使用的时候就是用绑定类的类名。因为这里访问了类的私有成员,只有在其所在的类中才能被访问,因此必须指出类的作用域,不然就会报错。
//因为使用了命名空间,而Youth作为Closure的参数,使用非限定名称会报错,应该使用完全限定或者限定名称
$newSetValueFun = Closure::bind($setValueFun,$obj,'php\demo\part1\Youth');
//还可以直接这么写,省略掉上面实例化的步骤
//$newSetValueFun = Closure::bind($setValueFun,new Youth());
//通过$newSetValueFun来给实例化出来的对象中的public属性$name赋值
$newSetValueFun(45);
//激活Youth类中的魔术方法__tostring()方法来验证
echo $obj;
//经验证最后输出:一名年轻人的体重是45KG
与static属性绑定
namespace php\demo\part1;
use Closure;
//空行
//首先定义一个用来演示的类
class Youth
{
static $gender;
public function __toString(){
//非静态成员是通过this关键字和->结合来访问,因此public和private属性访问方法相同
return '一名年轻人的性别是'.static::$gender;
//另一种写法是
//return '一名年轻人的性别是'.Youth::$gender;或者return '一名年轻人的性别是'.self::$gender
}
}
//定义一个匿名函数,这个函数用来绑定youth类中的属性,用于设置类中属性的值,该函数接收1个参数
$setValueFun = function ($gender){
//因为这个函数将要和类绑定,绑定后就像类中已经定义的一个方法一样,在类中访问静态属性不能用$this,因为静态属性是所有对象共用的,只有一份,而$this代表具体的实例化对象
static::$gender = $gender;
};
//bind()是Closure类中的一个静态方法,其返回值是上面那个匿名函数的复制。
//该方法第一个参数代表要准备和类绑定的匿名函数,也就是上面$setvalue代表的匿名函数。
//该方法第二参数代表要绑定的类的一个实例,换个角度看就是说匿名函数中的this代表哪个实例化的对象,因为这里访问的是静态成员,不需要实例化的对象,在这个地方可以用null。
//该方法第三个参数代表类作用域,在使用的时候就是用绑定类的类名,在访问静态或者私有属性的时候必须加上这个参数。
//因为使用了命名空间,而Youth作为Closure的参数,使用非限定名称会报错,应该使用完全限定或者限定名称
$newSetValueFun = Closure::bind($setValueFun,null,Youth::class);
//还可以直接这么写
//$newSetValueFun = Closure::bind($setValueFun,null,'php\demo\part1\Youth');
$newSetValueFun('female');
//激活Youth类中的魔术方法__tostring()方法来验证
$obj = new Youth();
echo $obj;
//经验证最后输出:一名年轻人的性别是female
同时访问public、private、protected和static属性,和一个public方法
namespace php\demo\part1;
use Closure;
//空行
//首先定义一个用来演示的类
class Youth
{
public $name;
static $gender;
protected $age;
private $weight;
public function show(){
//非静态成员是通过this关键字和->结合来访问,因此public和private属性访问方法相同
return $this->name.'的性别是'.static::$gender.',今年'.$this->age.'岁,体重有'.$this->weight.'Kg';
}
}
//定义一个匿名函数,这个函数用来绑定youth类中的属性,用于设置类中属性的值,该函数接收2个参数
$setValueFun = function ($name,$gender,$age,$weight){
//因为这个函数将要和类绑定,绑定后就像类中已经定义的一个方法一样,因此在代码中要用$this->name来访问类中的属性
$this->weight = $weight;
$this->age = $age;
$this->name = $name;
static::$gender = $gender;
//通过闭包调用类中的方法
echo $this->show();
};
//bind()是Closure类中的一个静态方法,其返回值是上面那个匿名函数的复制。
//该方法第一个参数代表要准备和类绑定的匿名函数,也就是上面$setvalue代表的匿名函数。
//该方法第二参数代表要绑定的类的一个实例,换个角度看就是说匿名函数中的this代表哪个实例化的对象,在这段代码中没有单独new一个对象出来,而是在参数里直接new。
//该方法第三个参数代表类作用域,在使用的时候就是用绑定类的类名。因为这里访问了类的私有成员,只有在其所在的类中才能被访问,因此必须指出类的作用域,不然就会报错。
//因为使用了命名空间,而Youth作为Closure的参数,使用非限定名称会报错,应该使用完全限定或者限定名称
$newSetValueFun = Closure::bind($setValueFun,new Youth,'php\demo\part1\Youth');
$newSetValueFun('Lucy','female',21,45);
//经验证最后输出:Lucy的性别是female,今年21岁,体重有45Kg
bindto()绑定方法
namespace php\demo\part1;
use Closure;
//空行
//首先定义一个用来演示的类
class Youth
{
public $name;
static $gender = 'female';
protected $age = 18;
private $weight = 50;
public function show(){
//非静态成员是通过this关键字和->结合来访问,因此public和private属性访问方法相同
return $this->name.'的性别是'.self::$gender.',今年'.$this->age.'岁,体重有'.$this->weight.'Kg';
}
}
class user extends Youth{
//....
}
//定义一个匿名函数,这个函数先尝试修改类中静态成员gender的值,并将实例化对象中各成员的值输出
$setValueFun = function (){
self::$gender = 'male';
//因为这个函数将要和类绑定,绑定后就像类中已经定义的一个方法一样,因此在代码中要用$this->name来访问类中的属性
return $this->name.'的性别是'.self::$gender.',今年'.$this->age.'岁,体重有'.$this->weight.'Kg';
};
//将Youth类实例出一个对象,并给各赋值
$obj = new user();
$obj->name = 'Lily';
//再实例化一个对象,用来对比
$obj1 = new user();
$obj1->name = 'Lucy';
//bindto()是Closure类中的一个方法,其返回值是个匿名函数。
//该方法第一参数代表要绑定的类的一个实例,换个角度看就是说匿名函数中的this代表哪个实例化的对象,也就是this取值是多少。
//该方法第二个参数代表类作用域,在使用的时候就是用绑定类的类名。
//示例一:演示调用父类和子类的区别,会发现在调用子类时private属性因为不能继承,而无法显示
$newSetValueFun =$setValueFun->bindto($obj,'php\demo\part1\Youth');
echo $newSetValueFun();
echo '<br>';
//输出Lily的性别是male,今年18岁,体重有50Kg
$newSetValueFun =$setValueFun->bindto($obj,'php\demo\part1\user');
echo $newSetValueFun();
echo '<br>';
//输出Lily的性别是male,今年18岁,体重有Kg,发现这里的体重没有了
//示例二:演示调用不同对象时,得到的结果不一样
$newSetValueFun =$setValueFun->bindto($obj,'php\demo\part1\Youth');
echo $newSetValueFun();
echo '<br>';
//输出Lily的性别是male,今年18岁,体重有50Kg
$newSetValueFun =$setValueFun->bindto($obj1,'php\demo\part1\Youth');
echo $newSetValueFun();
echo '<br>';
//输出Lucy的性别是male,今年18岁,体重有50Kg
//你会发现虽然$obj和$obj1都是子类user实例化出来的对象,但是因为bingto()中最后一个参数都是Youth类,所以private属性weight的值还是能显示出来
//同时,因为$obj和$obj1中对name属性赋值不一样,也导致最后输出的结果不一样。