博客列表 >多态与魔术方法

多态与魔术方法

手机用户1631860753
手机用户1631860753原创
2021年10月26日 00:23:17562浏览

一.静态成员

  • 静态成员的优缺点:

优点:

1.存在多个实例,但是静态成员在内存中,只占一份
2.静态成员,执行效率比实例化高

缺点:

静态成员不能自动销毁,实例化就会自动销毁

  • 静态是多态的一种
  • 静态也是可以被继承的
  • 子类继承父类,访问父类的静态方法是用子类的 类名:: 进行访问

二.抽象类

  • 抽象类也是多态的一种
  • 抽象类用于描述一些事物所具有的的特性和行为,但是没有具体实现
  • 抽象类,有类也有方法,但是没有实例
  • 关键词:abstract 写在class前面
  • 抽象类可以继承抽象类
  • 继承了抽象类,那么就要把抽象类里面的所有方法都重写,不然会报错
  • 如果继承了抽象类,但是不能把所有方法都重写,那么只能把自己也变成抽象类
  • 抽象类里可以可以有普通的方法
  • 构造方法也可以在抽象类里使用
  • 抽象类:设计类与实现类是分离的,可以为子类提供一些,公用的方法,作为子类重写的模板来使用

  • 创建抽象类

  1. // 创建抽象类
  2. abstract class A
  3. {
  4. // 抽象方法
  5. abstract public function ff1();
  6. abstract public function ff2();
  7. }
  8. // new A(); // 抽象类不能实例化,不能生产出来对象,但是可以通过继承抽象类进行实例化
  9. // 抽象类继承抽象类,
  10. abstract class B extends A
  11. {
  12. // 构造方法在抽象类里使用
  13. protected $name1;
  14. protected $name2;
  15. public function __construct($name1, $name2)
  16. {
  17. $this->name1 = $name1;
  18. $this->name2 = $name2;
  19. }
  20. // 继承了抽象类,抽象类里的所有抽象方法也要重写,
  21. // 如果抽象类方法不全部都重写,那么只能自己也转变为抽象类
  22. // 抽象类里面也可以使用普通方法
  23. public function ff1()
  24. {
  25. return '我是: ' . $this->name1 . ',继承的抽象类A重写ff1';
  26. }
  27. }
  28. // 继承抽象类B 重写B没有重写的方法
  29. class C extends B
  30. {
  31. public function ff2()
  32. {
  33. return '我是: ' . $this->name2 . ',继承的抽象类B重写抽象类A中的ff2';
  34. }
  35. }
  36. $a = new C('ff1', 'ff2');
  37. echo $a->ff1();
  38. echo '<hr>';
  39. echo $a->ff2();
  • 输出

三.类常量

  • 类里面也有常量,被当成静态的成员
  • 有一些数据不能让别人更改的,就会用到常量
  • 不能用普通方法访问常量,要用静态方法访问 类名::
  • 类常量关键词:const

  • 常量

    1. class Cl
    2. {
    3. // const 常量关键词
    4. const CL_NAME = '常量';
    5. // 不能用普通方法访问,要用静态访问方法 类名::
    6. public function get_name()
    7. {
    8. return self::CL_NAME;
    9. }
    10. }
    11. echo Cl::CL_NAME;
    12. $obj = new Cl();
    13. echo $obj->get_name();

四.接口

  • 接口也是多态的一种,不管是普通类还是抽象类,都是单继承,就是一个子类只能继承一个父类
  • 那我们要一个类继承多个类,经过发展,接口实现了这个功能,它可以实现多个父类
  • 创建接口关键词: interface 是替换class
  • 接口只允许声明两个成员:1.常量,2.抽象方法
  • 接口不能继承,如果继承了就和单继承一样了
  • 使用接口关键词: implements 实现接口
  • 使用多个接口要用英文逗号隔开
  • 使用接口的时候,如果接口里有静态成员,重写的时候也要按照静态的方法写

  • 接口的运用

  1. // 创建抽象类
  2. abstract class A
  3. {
  4. // const 常量
  5. const APP_NAME = 'Mac';
  6. // 抽象方法
  7. abstract public function az($cj);
  8. }
  9. // 关键词 interface 创建接口
  10. interface Cja
  11. {
  12. public static function az_Cja($a);
  13. }
  14. interface Cjb
  15. {
  16. public function pj($b, $c);
  17. // 方法和函数一样,可以接收多个
  18. public function az_CJb($a);
  19. }
  20. // 用关键词 implements 来使用接口
  21. // 使用多个接口,用英文逗号隔开
  22. class B extends A implements Cja, Cjb
  23. {
  24. public function az($a)
  25. {
  26. return '安装成功: ' . $a;
  27. }
  28. // 使用接口,接口里有静态成员,那么重写的时候就要用静态的方法
  29. public static function az_Cja($a)
  30. {
  31. return '安装成功: ' . $a;
  32. }
  33. public function pj($b, $c)
  34. {
  35. return $b . '<hr>' . $c;
  36. }
  37. public function az_CJb($a)
  38. {
  39. return '安装成功: ' . $a;
  40. }
  41. }
  42. $obj = new B();
  43. echo $obj->pj('苹果台式电脑', '苹果笔记本');
  44. echo '<hr>';
  45. echo $obj->az('A安装包');
  46. echo '<hr>';
  47. echo B::az_Cja('B插件包'); // 静态成员用 类名:: 访问
  48. echo '<hr>';
  49. echo $obj->az_CJb('C插件包');

五.后期静态绑定

  • 后期静态绑定也叫延迟静态绑定,
  • 创建静态类属于前期, 静态::访问类就是后期
  • 后期静态绑定关键词:static 和静态成员关键词一样
  • 不管实例化谁,用了$this,它就会先找实例化的那个类里的方法
  • 静态继承的时候,是上下文环境,在调用过程中,没有正确识别调用者

  • 后期静态绑定的使用

  1. class A
  2. {
  3. public static function ff()
  4. {
  5. return '这是A类的ff';
  6. }
  7. public function show()
  8. {
  9. // return $this->ff(); // 静态成员不允许用 $this
  10. // return self::ff(); // 访问结果不匹配,要结果对应,实例化谁,就找谁拿结果
  11. return static::ff(); // 后期静态绑定,用 static关键词 替换 self关键词, 可以让实例化与结果匹配
  12. }
  13. }
  14. class B extends A
  15. {
  16. public static function ff()
  17. {
  18. return '这是B类的ff';
  19. }
  20. }
  21. $a = new A(); // 实例化 A
  22. echo $a->ff(); // 返回: 这是A类的ff
  23. echo '<hr>';
  24. $b = new B(); // 实例化 B
  25. echo $b->ff(); // 返回: 这是B类的ff

六.魔术方法

6.1 析构方法

  • __construct 构造方法,在new类的时候自动执行
  • __destruct 析构方法,在类注销(注销结束)的时候自动执行

  • 析构方法

  1. class A
  2. {
  3. public $name;
  4. public function __construct($name)
  5. {
  6. $this->name = $name;
  7. }
  8. // 析构方法是最后结束了执行
  9. public function __destruct()
  10. {
  11. echo '执行完了';
  12. }
  13. }
  14. $a = new A('析构方法');
  15. $name = $a->name;
  16. echo $a->name;
  17. echo '<hr>';
  18. unset($a); // 删除类,,相当于把类执行完了,结束这个类
  19. echo '<hr>';
  20. echo $name;

6.2 属性重载

  • __get 获取不可见和未定义的属性,触发这个魔术方法
  • __get 有一个参数,就相当于下标一样
  • 私有的和受保护的都可以使用
  • __set 修改成员的时候触发

  • 修改设置需要两个参数

    $key 相当于要修改的参数
    $value 相当于要修改的值

  • 通过返回 $this的key(参数名) = 要修改的值,进行修改

  • 不可见属性和未定义属性的获取与修改
  1. class A
  2. {
  3. protected $age;
  4. protected $jimi;
  5. private $name;
  6. public function __construct($name, $age, $jimi)
  7. {
  8. $this->name = $name;
  9. $this->age = $age;
  10. $this->jimi = $jimi;
  11. }
  12. // __get 有一个参数
  13. public function __get($n)
  14. {
  15. // 判断
  16. if ($n == 'name' || $n == 'age') {
  17. // return $name; // 这里的name和 类里的 $name 不是同一个
  18. // __get的参数: 我们要找的成员名字,我们在我们找name它就是name ,它就相当于是数组的下标一样
  19. // return $n;
  20. // $n 代表要找的成员名字
  21. return $this->$n;
  22. }
  23. // 判断它是否存在
  24. // empty 只要是没有值,也会当 true
  25. if (empty($this->$n)) {
  26. return '不存在';
  27. }
  28. return '抱歉,你暂时没有权限';
  29. }
  30. // 设置需要两个参数
  31. public function __set($key, $value)
  32. {
  33. // $key 相当于要修改的参数
  34. // $value 相当于要修改的值
  35. // 通过返回 $this的key(参数名) = 要修改的值,进行修改
  36. return $this->$key = $value;
  37. }
  38. }
  39. $a = new A('科学家', '25', '核心技术');
  40. echo $a->name . ',' . $a->age; // 科学家25
  41. echo '<hr>';
  42. echo $a->jimi; // 抱歉,你暂时没有权限
  43. echo '<hr>';
  44. $a->age = 30; // 修改参数
  45. echo $a->age; // 输出 30

6.3 方法重载

  • __call 访问未定义的方法时触发

  • __call 有两个参数

    第一个参数: 是访问的方法
    第二个参数: 是方法的传值

  • 示例

  1. class A
  2. {
  3. public function __call($key, $value)
  4. {
  5. return '方法名: ' . $key . '<br>方法参数: <pre>' . print_r($value, true) . '不存在';
  6. }
  7. }
  8. $a = new A();
  9. echo $a->adds(10, 30, 50);
  • 示例图

6.4 访问未定义的静态方法

  • __callStatic 访问未定义的静态方法时触发
  • 静态触发,就要使用静态方法
  • 没有静态方法访问,就会执行 __callStatic魔术方法

  • 示例

  1. class A
  2. {
  3. // 静态触发的话,就要使用静态方法
  4. public static function __callStatic($key, $value)
  5. {
  6. return '方法名: ' . $key . '<br>方法参数: <pre>' . print_r($value, true) . '不存在';
  7. }
  8. }
  9. // 没有这个静态方法,就会执行 __callStatic 魔术方法
  10. echo A::add(10, 30, 50);
  • 示例图

七.关键词与魔术方法

1.关键词:

关键词 解释
const 定义类常量
extends 扩展类,用一个类去扩展它的父类(继承类)
public 公开属性或者方法
protected 受保护的属性或者方法
private 私有属性或者方法
static 静态成员
abstract 抽象类或者方法
interface 创建接口
implements 实现接口
final 类不能被继承
parent:: 访问父类
$this 访问本类
self:: 访问本静态类
namespace 创建命名空间

2.魔术方法

方法 描述
__construct 构造方法,实例类的时候自动调用
__destruct 析构方法,类执行完后,自动调用
__call 在对象中调用一个不可访问方法时调用
__callStatic 用静态方式中调用一个不可访问方法时调用
__get 获取不可见和未定义的属性,自动调用
__set 修改成员的时候,自动调用
__isset 当对不可访问属性调用 isset()或 empty()时调用
__unset 当对不可访问属性调用unset()时被调用
__sleep 执行serialize()时,先调用这个函数
__wakeup 执行 unserialize()时,先会调用这个函数
__toString 类被当成字符串的回应方法
__invoke 调用函数的方式调用一个对象时的回应方法
__set_state 调用 var_export()导出类时,此静态方法会被调用
__clone 当对象复制完成时调用
__autoload 尝试加载未定义的类
__debugInfo 打印所需调试信息
声明:本文内容转载自脚本之家,由网友自发贡献,版权归原作者所有,如您发现涉嫌抄袭侵权,请联系admin@php.cn 核实处理。
全部评论
文明上网理性发言,请遵守新闻评论服务协议