博客列表 >0214作业(1)-闭包与对象绑定和自定义异常类基础知识-php培训十期线上班

0214作业(1)-闭包与对象绑定和自定义异常类基础知识-php培训十期线上班

Dseven
Dseven原创
2020年02月15日 10:08:31643浏览

1. 闭包与对象绑定

1.1 bind()绑定方法

  • 与public属性绑定
    1. //命名空间
    2. namespace php\demo\part1;
    3. //空行
    4. //首先定义一个用来演示的类
    5. class Youth
    6. {
    7. public $name;
    8. public function show(){
    9. //非静态成员是通过this关键字和->结合来访问
    10. return $this->name.'是一名年轻人';
    11. }
    12. }
    13. //定义一个匿名函数,这个函数用来绑定youth类中的属性,用于设置类中属性的值,该函数接收1个$name参数
    14. $setValueFun = function ($name){
    15. //因为这个函数将要和类绑定,绑定后就像类中的一个方法,因此在代码中要用$this->name来访问类中的属性
    16. $this->name = $name;
    17. };
    18. //将Youth类实例出一个对象
    19. $obj = new Youth();
    20. //bind()是Closure类中的一个静态方法,其返回值是上面那个匿名函数的复制。
    21. //该方法第一个参数代表要准备和类绑定的匿名函数,也就是上面$setvalue代表的匿名函数。
    22. //该方法第二参数代表要绑定的类的一个实例
    23. //该方法第三个参数代表类作用域,在使用的时候就是用绑定类的类名,因为这段代码只是设置public属性,因此可以省略。
    24. //下面代码中在Closure前面加上'\'是使用的完全限定名称,代表全局命名空间,也可以用use Closure来代替
    25. $newSetValueFun = \Closure::bind($setValueFun,$obj);
    26. //还可以直接这么写,省略掉上面实例化的步骤
    27. //$newSetValueFun = Closure::bind($setValueFun,new Youth());
    28. //通过$newSetValueFun来给实例化出来的对象中的public属性$name赋值
    29. $newSetValueFun('Lucy');
    30. //调用Youth类中的show方法来验证
    31. echo $obj->show();
    32. //经验证最后输出:Lucy是一名年轻人
  • 与private属性绑定(protected属性操作相同)
    1. //命名空间
    2. namespace php\demo\part1;
    3. use Closure;
    4. //空行
    5. //首先定义一个用来演示的类
    6. class Youth
    7. {
    8. private $weight;
    9. public function __toString(){
    10. //非静态成员是通过this关键字和->结合来访问,因此public和private属性访问方法相同
    11. return '一名年轻人的体重是'.$this->weight.'KG';
    12. }
    13. }
    14. //定义一个匿名函数,这个函数用来绑定youth类中的属性,用于设置类中属性的值,该函数接收2个参数
    15. $setValueFun = function ($weight){
    16. //因为这个函数将要和类绑定,绑定后就像类中已经定义的一个方法一样,因此在代码中要用$this->name来访问类中的属性
    17. $this->weight = $weight;
    18. };
    19. //将Youth类实例出一个对象
    20. $obj = new Youth();
    21. //bind()是Closure类中的一个静态方法,其返回值是上面那个匿名函数的复制。
    22. //该方法第一个参数代表要准备和类绑定的匿名函数,也就是上面$setvalue代表的匿名函数。
    23. //该方法第二参数代表要绑定的类的一个实例,换个角度看就是说匿名函数中的this代表哪个实例化的对象。
    24. //该方法第三个参数代表类作用域,在使用的时候就是用绑定类的类名。因为这里访问了类的私有成员,只有在其所在的类中才能被访问,因此必须指出类的作用域,不然就会报错。
    25. //因为使用了命名空间,而Youth作为Closure的参数,使用非限定名称会报错,应该使用完全限定或者限定名称
    26. $newSetValueFun = Closure::bind($setValueFun,$obj,'php\demo\part1\Youth');
    27. //还可以直接这么写,省略掉上面实例化的步骤
    28. //$newSetValueFun = Closure::bind($setValueFun,new Youth());
    29. //通过$newSetValueFun来给实例化出来的对象中的public属性$name赋值
    30. $newSetValueFun(45);
    31. //激活Youth类中的魔术方法__tostring()方法来验证
    32. echo $obj;
    33. //经验证最后输出:一名年轻人的体重是45KG
  • 与static属性绑定

    1. //命名空间
    2. namespace php\demo\part1;
    3. use Closure;
    4. //空行
    5. //首先定义一个用来演示的类
    6. class Youth
    7. {
    8. static $gender;
    9. public function __toString(){
    10. //非静态成员是通过this关键字和->结合来访问,因此public和private属性访问方法相同
    11. return '一名年轻人的性别是'.static::$gender;
    12. //另一种写法是
    13. //return '一名年轻人的性别是'.Youth::$gender;或者return '一名年轻人的性别是'.self::$gender
    14. }
    15. }
    16. //定义一个匿名函数,这个函数用来绑定youth类中的属性,用于设置类中属性的值,该函数接收1个参数
    17. $setValueFun = function ($gender){
    18. //因为这个函数将要和类绑定,绑定后就像类中已经定义的一个方法一样,在类中访问静态属性不能用$this,因为静态属性是所有对象共用的,只有一份,而$this代表具体的实例化对象
    19. static::$gender = $gender;
    20. };
    21. //bind()是Closure类中的一个静态方法,其返回值是上面那个匿名函数的复制。
    22. //该方法第一个参数代表要准备和类绑定的匿名函数,也就是上面$setvalue代表的匿名函数。
    23. //该方法第二参数代表要绑定的类的一个实例,换个角度看就是说匿名函数中的this代表哪个实例化的对象,因为这里访问的是静态成员,不需要实例化的对象,在这个地方可以用null。
    24. //该方法第三个参数代表类作用域,在使用的时候就是用绑定类的类名,在访问静态或者私有属性的时候必须加上这个参数。
    25. //因为使用了命名空间,而Youth作为Closure的参数,使用非限定名称会报错,应该使用完全限定或者限定名称
    26. $newSetValueFun = Closure::bind($setValueFun,null,Youth::class);
    27. //还可以直接这么写
    28. //$newSetValueFun = Closure::bind($setValueFun,null,'php\demo\part1\Youth');
    29. $newSetValueFun('female');
    30. //激活Youth类中的魔术方法__tostring()方法来验证
    31. $obj = new Youth();
    32. echo $obj;
    33. //经验证最后输出:一名年轻人的性别是female
  • 同时访问public、private、protected和static属性,和一个public方法

    1. //命名空间
    2. namespace php\demo\part1;
    3. use Closure;
    4. //空行
    5. //首先定义一个用来演示的类
    6. class Youth
    7. {
    8. public $name;
    9. static $gender;
    10. protected $age;
    11. private $weight;
    12. public function show(){
    13. //非静态成员是通过this关键字和->结合来访问,因此public和private属性访问方法相同
    14. return $this->name.'的性别是'.static::$gender.',今年'.$this->age.'岁,体重有'.$this->weight.'Kg';
    15. }
    16. }
    17. //定义一个匿名函数,这个函数用来绑定youth类中的属性,用于设置类中属性的值,该函数接收2个参数
    18. $setValueFun = function ($name,$gender,$age,$weight){
    19. //因为这个函数将要和类绑定,绑定后就像类中已经定义的一个方法一样,因此在代码中要用$this->name来访问类中的属性
    20. $this->weight = $weight;
    21. $this->age = $age;
    22. $this->name = $name;
    23. static::$gender = $gender;
    24. //通过闭包调用类中的方法
    25. echo $this->show();
    26. };
    27. //bind()是Closure类中的一个静态方法,其返回值是上面那个匿名函数的复制。
    28. //该方法第一个参数代表要准备和类绑定的匿名函数,也就是上面$setvalue代表的匿名函数。
    29. //该方法第二参数代表要绑定的类的一个实例,换个角度看就是说匿名函数中的this代表哪个实例化的对象,在这段代码中没有单独new一个对象出来,而是在参数里直接new。
    30. //该方法第三个参数代表类作用域,在使用的时候就是用绑定类的类名。因为这里访问了类的私有成员,只有在其所在的类中才能被访问,因此必须指出类的作用域,不然就会报错。
    31. //因为使用了命名空间,而Youth作为Closure的参数,使用非限定名称会报错,应该使用完全限定或者限定名称
    32. $newSetValueFun = Closure::bind($setValueFun,new Youth,'php\demo\part1\Youth');
    33. $newSetValueFun('Lucy','female',21,45);
    34. //经验证最后输出:Lucy的性别是female,今年21岁,体重有45Kg

    1.2 bindto()绑定方法

    1. //命名空间
    2. namespace php\demo\part1;
    3. use Closure;
    4. //空行
    5. //首先定义一个用来演示的类
    6. class Youth
    7. {
    8. public $name;
    9. static $gender = 'female';
    10. protected $age = 18;
    11. private $weight = 50;
    12. public function show(){
    13. //非静态成员是通过this关键字和->结合来访问,因此public和private属性访问方法相同
    14. return $this->name.'的性别是'.self::$gender.',今年'.$this->age.'岁,体重有'.$this->weight.'Kg';
    15. }
    16. }
    17. class user extends Youth{
    18. //....
    19. }
    20. //定义一个匿名函数,这个函数先尝试修改类中静态成员gender的值,并将实例化对象中各成员的值输出
    21. $setValueFun = function (){
    22. self::$gender = 'male';
    23. //因为这个函数将要和类绑定,绑定后就像类中已经定义的一个方法一样,因此在代码中要用$this->name来访问类中的属性
    24. return $this->name.'的性别是'.self::$gender.',今年'.$this->age.'岁,体重有'.$this->weight.'Kg';
    25. };
    26. //将Youth类实例出一个对象,并给各赋值
    27. $obj = new user();
    28. $obj->name = 'Lily';
    29. //再实例化一个对象,用来对比
    30. $obj1 = new user();
    31. $obj1->name = 'Lucy';
    32. //bindto()是Closure类中的一个方法,其返回值是个匿名函数。
    33. //该方法第一参数代表要绑定的类的一个实例,换个角度看就是说匿名函数中的this代表哪个实例化的对象,也就是this取值是多少。
    34. //该方法第二个参数代表类作用域,在使用的时候就是用绑定类的类名。
    35. //示例一:演示调用父类和子类的区别,会发现在调用子类时private属性因为不能继承,而无法显示
    36. $newSetValueFun =$setValueFun->bindto($obj,'php\demo\part1\Youth');
    37. echo $newSetValueFun();
    38. echo '<br>';
    39. //输出Lily的性别是male,今年18岁,体重有50Kg
    40. $newSetValueFun =$setValueFun->bindto($obj,'php\demo\part1\user');
    41. echo $newSetValueFun();
    42. echo '<br>';
    43. //输出Lily的性别是male,今年18岁,体重有Kg,发现这里的体重没有了
    44. //示例二:演示调用不同对象时,得到的结果不一样
    45. $newSetValueFun =$setValueFun->bindto($obj,'php\demo\part1\Youth');
    46. echo $newSetValueFun();
    47. echo '<br>';
    48. //输出Lily的性别是male,今年18岁,体重有50Kg
    49. $newSetValueFun =$setValueFun->bindto($obj1,'php\demo\part1\Youth');
    50. echo $newSetValueFun();
    51. echo '<br>';
    52. //输出Lucy的性别是male,今年18岁,体重有50Kg
    53. //你会发现虽然$obj和$obj1都是子类user实例化出来的对象,但是因为bingto()中最后一个参数都是Youth类,所以private属性weight的值还是能显示出来
    54. //同时,因为$obj和$obj1中对name属性赋值不一样,也导致最后输出的结果不一样。
  • 补充知识
    • 类中static成员在内存中是有且唯有一个固定地址的,不因实例化出来的对象变化而变化,而类中public、protected、private成员在内存中没有固定的地址,有多少实例化的对象就有多少个。
    • bind复制一个闭包,绑定指定的 $this 对象和类作用域。把一个闭包转换为某个类的方法 (只是这个方法不需要通过对象调用), 这样闭包中的 $this、static、self 就转换成了对应的对象或类。
      • 只绑定 $this 对象.\将对象作为bind中的第二个参数,第三个参数不要。(bindto中的第一个)
      • 只绑定类作用域.\将类名作为bind中的第三个参数,第二个参数为null,相当于在类中增加了一个静态方法。(bindto中的第二个)
      • 同时绑定 $this 对象和类作用域.第二个和第三个参数都要,相当于在类中加入了一个成语方法。(bindto中的第一个和第二个)
      • 都不绑定.(这样一来只是纯粹的复制,文档说法是使用 cloning 代替 bind 或 bindTo)

ps.作业太长,分两次提交

声明:本文内容转载自脚本之家,由网友自发贡献,版权归原作者所有,如您发现涉嫌抄袭侵权,请联系admin@php.cn 核实处理。
全部评论
文明上网理性发言,请遵守新闻评论服务协议