Blogger Information
Blog 26
fans 0
comment 0
visits 21808
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
静态绑定与拦截器
溪边小树
Original
626 people have browsed it

继承、抽象类、接口、trait要点整理

近期学习了面向对象编程中一些比较抽象的概念,在此对部分重点内容的要点做一下整理小结。
1、类的继承,也叫类的扩展(父类: 基类、子类: 扩展类)
二类成员: 子类有权访问的父类成员类型, public, protected
三种操作: 子类对父类的三种操作: 继承, 重写, 扩展

  1. 继承: 父类的二类成员自动成为子类的成员
  2. 重写: 覆写与父类/基类同名的成员(属性, 方法)
  3. 扩展: 子类添加自身的方法来增加/扩展父类的功能

2、抽象类: 部分分离了设计(抽象类中完成)与实现(工作类中完成)
设计类:具体方法,有方法体: {…};抽象方法:没有方法体,
只要一个类中有一个抽象方法, 那么这个类就是:抽象类

实现类/工作类: 是一个可以被实例化的普通类,最终工作类: 允许实例化
工作类不一定是可以被实例化的普通类,也可是一个抽象类
抽象类也可以被继承, 抽象类也可以用在继承的上下文环境中
抽象类中允许有抽象成员, 但不是强制的,也可以没有。
必须将抽象类中的抽象方法实现

3、接口: 完全分离了”设计与实现”,关键字: interface,
使用与类相似的语法: 抽象方法, 常量, 构造方法(魔术方法的一种),
默认访问控制必须是public,接口允许多继承, 从而间接实现了PHP的多继承,implements (英婆慢吃),单接口, 工作类实现接口 接口常量的访问与类常量一样。多接口继承,一个接口同时继承多个接口,接口可以突破php类的继承限制, 允许多继承, 形成了多层级的接口。
用抽象类来部分实现一个接口,接口是实现多态的重要手段。
因为是面向接口编程, DB_PDO, DB_MySQLi都实现了同一接口,只要将对象参数的类型限定在接口上就可以实现多态,至于选用哪个类实例,由用户自行选择。

4、trait: php5.4+, 代码复用,与抽象类,接口一样不能实例化, 只能嵌入到宿主类中使用,它是一个特殊类: 1. 常规, 2. 静态, 3. 抽象, 不能用类常量。
类中使用trait , 用use 关键,将use tDemo理解为加载。
trait 功能1: 代码复用;trait2: 在继承上下文环境中, 具有优先级, 通过优先的设置, 降低单继承的影响。
trait中的同名方法将父类中同名方法覆盖了, 重写了;当前类的同名方法又会覆盖掉trait中同名方法;方法使用的优先级:子类 > trait > 父类。Trait组合的同名方法的命名冲突的解决方案:一是替换,用关键字insteadOf,二是别名,用关键字as,as 还可以修改trait成员的访问控制。

静态绑定与拦截器

1、实例演示后期静态绑定的原理与实现

  1. <?php
  2. // 后期静态绑定: 又叫延迟静态绑定
  3. // 后期静态绑定工作在: 静态继承上下文的环境中
  4. abstract class CreateInstance
  5. {
  6. }
  7. // 实现类1
  8. class User extends CreateInstance
  9. {
  10. public static function create() : self
  11. {
  12. return new self();
  13. }
  14. }
  15. // 实现类2
  16. class Product extends CreateInstance
  17. {
  18. public static function create() : self
  19. {
  20. return new self();
  21. }
  22. }
  23. // 客户端
  24. $user = User::create();
  25. var_dump($user);
  26. echo '<hr>';
  27. $product = new Product();
  28. var_dump($product);
  29. ----------------------
  30. // 将demo1.php中的代码进行简化, 将类实例的创建过程上移到它的基类中
  31. abstract class CreateInstance
  32. {
  33. public static function create()
  34. {
  35. // 出错原因: self 代表当前类,而当前是抽象类, 不能实例化, 不能用new 调用
  36. // 解决:将类的定义与类的调用完全分离开
  37. // 方案: 后期静态绑定, 使用关键字: static, 将self 替换掉
  38. // return new self();
  39. return new static();
  40. // 程序执行有二个过程: 编译, 执行
  41. // 类方法与有一个调用上下文, 定义上下文
  42. // self: self始终与定义该方法(属性)的类进行绑定
  43. // static: static总是自动与该方法(属性)调用类进行绑定
  44. // self: 与定义类绑定
  45. // static: 与调用类绑定
  46. }
  47. }
  48. // 实现类1
  49. class User extends CreateInstance
  50. {
  51. }
  52. // 实现类2
  53. class Product extends CreateInstance
  54. {
  55. }
  56. // 客户端
  57. $user = User::create();
  58. var_dump($user);
  59. echo '<hr>';
  60. $product = Product::create();
  61. var_dump($product);
  62. ---------------------
  63. // 后期静态绑定的应用场景: 动态绑定静态成员的调用上下文
  64. // 调用上下文者: 调用者
  65. class Base
  66. {
  67. // 静态方法: 允许重写
  68. public static function index()
  69. {
  70. return '当前调用方法: ' . __METHOD__;
  71. }
  72. public static function fetch()
  73. {
  74. // return self::index();
  75. return static::index();
  76. }
  77. }
  78. class User extends Base
  79. {
  80. // 重写父类中的静态方法: index()
  81. public static function index()
  82. {
  83. return '当前调用方法: ' . __METHOD__;
  84. }
  85. }
  86. // 客户端
  87. // echo Base::fetch();
  88. echo User::fetch();

2、魔术方法之构造方法与析构方法

  1. <?php
  2. // 魔术方法:
  3. // 语法: 类中有一些方法总是使用双下划线开头, 这就叫魔术方法
  4. // 调用者: 由系统根据一定的条件或用户行为, 自动调用/触发, 禁止用户主动调用
  5. // 构造方法: __construct(), 是类的实例化过程中被自动调用, new 的时候
  6. class Scorelist
  7. {
  8. private $course;
  9. private $score;
  10. // 在实例化的时候,自动完成类属性的初始化/赋值,如何做到呢?
  11. // 构造方法: 构造器, 功能就是生成一个新对象
  12. public function __construct($course, $score)
  13. {
  14. // 1. 生成一个新对象/类实例
  15. // $this是由php接管的对象, 不能用户设置, 下面是伪代码,辅助理解
  16. // $this = new self();
  17. // 2. 初始化这个新对象: 给这个新对象添加属性并赋值, 或自动执行某些操作方法
  18. $this->course = $course;
  19. $this->score = $score;
  20. $this->write();
  21. // 3. 返回这个刚刚创建并初始化的对象
  22. // 隐式返回当前新生的类实例, 不用显式返回, 自动完成
  23. // return $this;
  24. }
  25. // 类方法
  26. public function write()
  27. {
  28. echo "$this->course : $this->score 分<hr>";
  29. }
  30. // 析构方法, 没有参数, 销毁/删除一个对象的时候调用
  31. public function __destruct()
  32. {
  33. echo "Destroying " . $this->score ;
  34. }
  35. }
  36. // 客户端
  37. $Scorelist1 = new Scorelist('PHP网络编程', 90);
  38. //var_dump($Scorelist1);

3、实例演示属性重载/拦截器的所有方法

  1. <?php
  2. // 重载: php中的重载与其它语言不同(C++/Java), 称为"访问拦截器"更贴切
  3. // 拦截器: 属性拦截器, 方法拦截器
  4. // 使用场景: 当用户访问一个不存在的或无权限访问属性/方法时, 自动调用
  5. // 访问: 包括二个操作:就是读和写, 或者称为: 查询和设置
  6. // 属性拦截器: __set(), __get(), __isset(), __unset()
  7. class Product
  8. {
  9. private $name;
  10. private $price;
  11. private $taxRate = 0.06;
  12. public function __construct($name, $price)
  13. {
  14. $this->name = $name;
  15. $this->price = $price;
  16. }
  17. // 1. 属性查询拦截器
  18. public function __get($property)
  19. {
  20. // return $this->$property;
  21. // return $property === 'name' ? $this->name : '无权访问';
  22. // 拦截转发器
  23. // 1. 先事先约定一些方法专用于处理属性访问
  24. $method = 'get' . ucfirst($property);
  25. // 2. 转发访问请求
  26. return method_exists($this, $method) ? $this->$method() : null;
  27. }
  28. private function getName()
  29. {
  30. return mb_substr($this->name, 0, 5) . '...';
  31. }
  32. private function getPrice()
  33. {
  34. return $this->price + $this->price * $this->taxRate;
  35. }
  36. // 2. 属性设置拦截器
  37. public function __set($property, $value)
  38. {
  39. $method = 'set' . ucfirst($property);
  40. // 转发访问请求
  41. return method_exists($this, $method) ? $this->$method($value) : null;
  42. }
  43. private function setName($value)
  44. {
  45. $this->name = trim($value);
  46. }
  47. private function setPrice($value)
  48. {
  49. if ($value === null) unset($this->price);
  50. else $this->price = $value * (1-$this->taxRate);
  51. }
  52. // 3. 属性检测拦截器
  53. public function __isset($property)
  54. {
  55. return $property === 'name' ? isset($this->name) : false;
  56. }
  57. // 4. 属性销毁拦截器
  58. public function __unset($property)
  59. {
  60. if ($property === 'price') {
  61. $method = 'set' . ucfirst($property);
  62. // 转发访问请求
  63. if (method_exists($this, $method)) return $this->$method(null) ;
  64. }
  65. }
  66. }
  67. // 客户端
  68. $product = new Product('一坛绍兴女儿红',520);
  69. // 访问了一个无访问权限的类属性
  70. echo $product->name;
  71. echo $product->price;
  72. echo '<hr>';
  73. $product->name = '一辆8手的夏利';
  74. $product->price = 2000;
  75. echo $product->name;
  76. echo $product->price;
  77. echo '<hr>';
  78. echo isset($product->name) ? '存在' : '不存在';
  79. echo isset($product->price) ? '存在' : '不存在';
  80. unset($product->name);
  81. echo $product->name;
  82. unset($product->price);
  83. echo $product->price;

4、实例演示方法重载/拦截器的所有方法

  1. <?php
  2. // 方法拦截器, 其实比属性拦截器更有用
  3. // __call(), __callStatic()
  4. class User
  5. {
  6. // 方法拦截器
  7. public function __call($name, $arguments)
  8. {
  9. printf('方法名: %s , 参数: [%s]', $name, implode(', ', $arguments));
  10. }
  11. // 静态方法拦截器
  12. public static function __callStatic($name, $arguments)
  13. {
  14. printf('静态方法名: %s , 参数: [%s]', $name, implode(', ', $arguments));
  15. }
  16. }
  17. $user = new User();
  18. $user->demo(1,2,3,4);
  19. echo '<br>';
  20. User::demo(6,7,8,9);

课程学习小结

本次课程老师从浅显易懂的实例出发,详解介绍了静态绑定与拦截器相关内容,通过回看视频及讲义代码,加深了理解, 并通过修改实现部分代码,同时对前期学习的内容作了阶段性的回顾和整理,感觉非常有必要。

Correcting teacher:天蓬老师天蓬老师

Correction status:qualified

Teacher's comments:不建议将多天作业合并完成的, 不方便核对完成情况, 下次注意, 不过写得不错
Statement of this Website
The copyright of this blog article belongs to the blogger. Please specify the address when reprinting! If there is any infringement or violation of the law, please contact admin@php.cn Report processing!
All comments Speak rationally on civilized internet, please comply with News Comment Service Agreement
0 comments
Author's latest blog post