博客列表 >1. 类的静态成员、类引用self:: 2. 接口、抽象类、trait 3. 后期静态绑定 static:: 4.USE在命名空间中的使用

1. 类的静态成员、类引用self:: 2. 接口、抽象类、trait 3. 后期静态绑定 static:: 4.USE在命名空间中的使用

尹辉
尹辉原创
2023年04月26日 12:33:33299浏览

4.8.10 类的静态成员、类常量

静态成员、类常量是属于类本身,不需要实例化就可以被访问到,直接使用类名访问,减少实例化对象所占内存。

  1. static 标识静态成员(默认为 public,可以不写)

  2. const 类常量(不能用 define ),通常在类内部使用,不建议在类外部使用

  3. 在类内部,使用 self::访问静态成员(需要加$)、类常量(不需要加$),(不能使用 $this)

  4. __callStatic 当调用不存在或者没有权限访问的静态方法时,此魔术方法会被调用

  5. :: 范围解析符 self::用于类常量 静态成员的访问

  6. 类外部访问:className::静态成员(需要加$),className::类常量(不需要加$)
  1. class Teacher
  2. {
  3. // 类常量
  4. public const CATES = ['前端', '后端', '全栈'];
  5. // 静态属性
  6. public static $uname;
  7. private static $salary;
  8. // 不加访问控制,默认为 public
  9. static $siteName = 'php中文网';
  10. static $count = 0;
  11. // 构造方法,创建对象时初始化属性
  12. public function __construct($uname, $salary)
  13. {
  14. //静态成员与类的实例无关 不能使用$this来访问 使用self::访问静态成员 类常量
  15. self::$salary = $salary;
  16. self::$uname = $uname;
  17. self::$count++;
  18. }
  19. static function getBK()
  20. {
  21. // 非静态成员是对象级别的存在,静态成员是类级别的存在,随着类的加载而加载,优先于对象存在的,在静态方法中无法访问非静态成员(此时还不存在对象)
  22. return self::$uname . '来自' . self::$siteName . '可以胜任' . join(',', self::CATES) . '的相关课程';
  23. }
  24. }
  25. $mj = new Teacher('灭绝师妹', 2000);
  26. echo Teacher::$uname; // 灭绝师妹
  27. // 可以使用对象来访问,但不建议
  28. echo $mj::$uname; // 灭绝师妹
  29. $mj1 = new Teacher('灭绝老师', 5000);
  30. // 实例化对象会改变静态属性的值,值为最后一次实例化的值,也会改变之前实例化的对象
  31. echo Teacher::$uname; // 灭绝老师
  32. echo $mj::$uname; // 灭绝老师
  33. //类常量不建议在类外访问
  34. print_r(Teacher::CATES); // Array ( [0] => 前端 [1] => 后端 [2] => 全栈 )
  35. // 访问静态方法
  36. echo Teacher::getBK(); // 灭绝老师来自php中文网可以胜任前端,后端,全栈的相关课程
  37. // 访问次数
  38. echo Teacher::$count; // 2

4.8.11 接口、抽象类、trait

4.8.11.1 接口、抽象类

  • 接口(interface)是定义,类(class)是实现。

    • 接口(interface):定义方法(只有声明,没有实现),不能被实例化
    • 抽象类(abstract):继承接口(interface),重写并实现部分方法,不能被实例化,可以继承多个接口
    • 类(class):继承抽象类,实现全部方法,可以实例化,只能继承一个父类(抽象类)
  1. // 接口(interface)
  2. interface iDemo
  3. {
  4. // 所有成员必须是公开的(public)
  5. public const gender = 'MALE';
  6. // 接口(interface)所有方法都是抽象方法 只有声明 没有实现
  7. public function sum($a, $b);
  8. public function sub($a, $b);
  9. public function mul($a, $b);
  10. public function div($a, $b);
  11. }
  12. interface test
  13. {
  14. public const T = 20;
  15. }
  16. // 抽象类(abstract):
  17. // 抽象类 可以存在 抽象方法和工作方法 不能被实例化
  18. // 抽象类可以继承多个接口
  19. // 实现部分方法,剩余方法由类(class)完成
  20. abstract class aDemo implements iDemo, test
  21. {
  22. // 重写接口 iDemo 中的 sum 方法
  23. public function sum($a, $b)
  24. {
  25. return $a + $b;
  26. }
  27. // 重写接口 iDemo 中的 sub 方法
  28. public function sub($a, $b)
  29. {
  30. return $a - $b;
  31. }
  32. }
  33. // 类只能继承一个父类(抽象类)
  34. // 类(class):实现全部方法,可以实例化
  35. class Work extends aDemo
  36. {
  37. // 重写接口 iDemo 中的 mul 方法
  38. public function mul($a, $b)
  39. {
  40. // 调用接口 test 中的常量 T
  41. echo self::T;
  42. return $a * $b;
  43. }
  44. // 重写接口 iDemo 中的 div 方法
  45. public function div($a, $b)
  46. {
  47. return $a / $b;
  48. }
  49. }
  50. $obj = new Work;
  51. $obj->mul(5,6); // 20 ( echo self::T; )
  52. echo $obj->sum(10, 20); // 30

4.8.11.2 trait

  • trait是基于类的语法,但是和接口一样,不能被实例化 ,是对类功能的横向扩展。

  • php oop 默认是单继承 只能继承一个父类->高耦合

  • 一个类可以实现多个接口,多态
  • trait 功能组合式地实现多继承
  1. // 接上例的接口和抽象类
  2. // 定义 trait,扩展类的功能
  3. // 断点打印 t1
  4. trait t1
  5. {
  6. public function dd($data)
  7. {
  8. var_dump($data);
  9. die;
  10. }
  11. }
  12. // 扩展 sum() 功能
  13. trait t2
  14. {
  15. public function sum($a, $b, ...$args)
  16. {
  17. return $a + $b + array_sum($args);
  18. }
  19. }
  20. class Work extends aDemo
  21. {
  22. // 同名方法优先级 类同名方法(重写)>trait>继承成员方法
  23. //trait 功能组合式地实现多继承
  24. use t1, t2;
  25. // 重写接口 iDemo 中的 mul 方法
  26. public function mul($a, $b)
  27. {
  28. // 调用接口 test 中的常量 T
  29. echo self::T;
  30. return $a * $b;
  31. }
  32. // 重写接口 iDemo 中的 div 方法
  33. public function div($a, $b)
  34. {
  35. return $a / $b;
  36. }
  37. // 类同名方法(重写),优先级最大
  38. // public function sum($a, $b)
  39. // {
  40. // return 'hello';
  41. // }
  42. }
  43. echo $obj->sum(10, 20, 30, 40, 200); // 300 (trait t2)
  44. $obj->dd('你好'); // 你好(trait t1)

4.8.12 后期静态绑定

self:: 对当前类的静态引用是由限制的,self::取决于定义当前方法所在的类, 定义类与调用类(实例化的对象)不能动态绑定

  1. class Car
  2. {
  3. // 私有静态方法 getName()
  4. private static function getName(): string
  5. {
  6. return 'car';
  7. }
  8. public static function run()
  9. {
  10. // self:: 指向当前类,实例化的对象中依然指向当前类 Car
  11. return self::getName();
  12. }
  13. }
  14. class Benz extends Car
  15. {
  16. // 重写父类的静态方法 getName()
  17. public static function getName()
  18. {
  19. return 'E300';
  20. }
  21. }
  22. echo Car::run(); // car
  23. // 调用类中 self::还是指向父类 Car,而不是指向调用类 Benz
  24. echo Benz::run(); // car

使用后期静态绑定 static::,不再被解析为定义当前方法所在的类,而是在调用类。

  1. class Car
  2. {
  3. private static function getName(): string
  4. {
  5. return 'car';
  6. }
  7. public static function run()
  8. {
  9. // self:: 改为 static::
  10. return static::getName();
  11. }
  12. }
  13. class Benz extends Car
  14. {
  15. public static function getName()
  16. {
  17. return 'E300';
  18. }
  19. }
  20. echo Car::run(); // car
  21. // 后期静态绑定 static::,不再指向父类 Car,而是指向调用类 Benz
  22. echo Benz::run(); // E300

4.8.13 命名空间

  • 全局成员: 常量、命名函数、类(接口),不受作用域限制,重名的话会冲突

  • 命名空间:可以解决全局成员命名冲突的问题

    1. namespace ns1;
    2. class test
    3. {
    4. public static function show()
    5. {
    6. // __FUNCTION__ 只是返回方法(或者函数)的名字
    7. // __METHOD__ 返回类名和方法的名字(包括命名空间,如有)
    8. return __METHOD__;
    9. }
    10. }
    11. namespace ns2;
    12. class test
    13. {
    14. public static function show()
    15. {
    16. return __METHOD__;
    17. }
    18. }
    19. // 当前在命名空间 ns2,可以直接调用本空间下的类
    20. echo test::show(); // ns2\test::show
    21. // call_user_func() 回调,是异步,脱离了当前线程,不能直接调用,需要加上命名空间
    22. echo call_user_func(['test', 'show']); // 报错找不到test类
    23. echo call_user_func(['ns2\test', 'show']); // ns2\test::show
    24. // 从非全局命名空间(当前为 ns2)访问别的空间中的类 先回到root: \
    25. // 注意:这里的反斜杠(\)是空间分隔符,不是目录分隔符
    26. echo \ns1\test::show(); // ns1\test::show
  • 命名空间下的函数,优先级高于系统同名函数 (系统函数默认在全局命名空间)

    1. namespace demo;
    2. function var_dump($data)
    3. {
    4. echo 'var_dump' . $data;
    5. }
    6. var_dump('你好'); // var_dump你好

4.8.14 use 在命名空间中的使用

目录结构:

  • tp6
    • app
      • controller
        • Index.php
        • Login.php
    • autoload.php
    • index.php

app\controller 下面的两个类(命名空间设置为类所在的目录)

  • Index.php

    1. namespace app\controller;
    2. class Index
    3. {
    4. static function index()
    5. {
    6. return __METHOD__ . "<br />";
    7. }
    8. }
  • Login.php

    1. namespace app\controller;
    2. class Login
    3. {
    4. static function index()
    5. {
    6. return __METHOD__ . "<br />";
    7. }
    8. }

autoload.php:类的自动加载器

  1. spl_autoload_register(function ($className) {
  2. // 自动加载器引入的类名 $className 是带有命名空间的(app\controller\Index)
  3. // 命名空间名称与目录树对应,可以参与类文件所在位置的拼接
  4. // 命名空间的反斜杠(\)是空间分隔符,不是目录分隔符,需要转换为目录分割符
  5. // "\\":第一个 \ 是转义符,第二个 \ 是空间分隔符
  6. $file = str_replace("\\", DIRECTORY_SEPARATOR, $className) . '.php';
  7. if (is_file($file) && file_exists($file)) require $file;
  8. });

index.php:入口文件,使用 use 引入其他命名空间中的类

  1. // 入口文件
  2. // 注意:入口文件不能放在类所在的目录,否则无法引入
  3. require __DIR__ . DIRECTORY_SEPARATOR . 'autoload.php';
  4. // 1. 直接调用其他命名空间中的类,需加上命名空间
  5. // 无需 use app\controller;
  6. // 当前为全局命名空间,无需加 root:\
  7. echo app\controller\Index::index(); // app\controller\Index::index
  8. // 如果需要给命名空间起别名,则需要 use as
  9. use app\controller as ac;
  10. echo ac\login::index(); // app\controller\Login::index
  11. // 2. use 引入其他命名空间中的类,然后可以直接调用改类
  12. use app\controller\Index;
  13. use app\controller\Login;
  14. echo Index::index(); // app\controller\Index::index
  15. echo Login::index(); // app\controller\Login::index
  16. // 给引入的类起别名: use as
  17. // 不起别名,默认为Index
  18. use app\controller\Index as in;
  19. echo in::index(); // app\controller\Index::index
上一条:Linux 指令下一条:实现mvc路由映射
声明:本文内容转载自脚本之家,由网友自发贡献,版权归原作者所有,如您发现涉嫌抄袭侵权,请联系admin@php.cn 核实处理。
全部评论
文明上网理性发言,请遵守新闻评论服务协议