博客列表 >面向对象编程基础

面向对象编程基础

残破的蛋蛋
残破的蛋蛋原创
2021年02月04日 14:42:03622浏览

面向对象编程基础

一、什么是面向对象?

面向对象编程(Object Oriented Programming),简称OOP。

它将真实世界各种复杂的关系,抽象为一个个对象,然后由对象之间的分工与合作,完成对真实世界的模拟。

面向对象的特性:

  1. 封装性
  2. 继承性
  3. 抽象(多态性)

二、类的声明与实例化

在声明一个类时,使用class关键字,声明这个类的与这个类所在的文件最好同名。

  • 以下是声明了一个Student类:
  1. class Student {
  2. // 在这里面声明成员属性和方法
  3. }

类的属性和方法有三种:

  1. public: 公开的,外部可以访问的;
  2. protected: 受保护的,仅限本类和子类访问;
  3. private: 私有,仅限本类使用,外部和子类无法访问。

以下是声明了一个Student类,以及类中的属性和方法的案例。

  1. class Student
  2. {
  3. // 属性:变量
  4. // 公有属性,外部、本类和子类可以访问
  5. public $name;
  6. // 受保护成员,仅限本类以及子类访问
  7. protected $gender;
  8. // private: 私有成员,仅限本类中的使用
  9. private $age;
  10. private static $score;
  11. // 构造函数
  12. // __construct()属于魔术方法,由系统自动调用
  13. // 在类的实例化过程中会调用它
  14. public function __construct($name, $gender, $age)
  15. {
  16. $this->name = $name;
  17. $this->gender = $gender;
  18. $this->age = $age;
  19. }
  20. // 方法
  21. public function getStuInfo() {
  22. return "姓名:{$this->name},性别:{$this->gender},年龄:{$this->age}岁。";
  23. }
  24. }

实例化Student类:

  1. $stu = new Student('张三', '男', 16);
  2. echo $stu->getStuInfo();

以上结果将输出:姓名:张三,性别:男,年龄:16岁。

访问类中的公有属性:

  1. echo $stu->name; // 张三

三、静态方法和成员(static)

当一个类的成员或方法被声明成了静态(static),那么,就无法通过类实例去访问了,必须使用类直接调用。

  1. class Staff {
  2. public $name;
  3. // 静态成员
  4. public static $salary;
  5. // 构造函数
  6. public function __construct(string $name, int $salary)
  7. {
  8. $this->name = $name;
  9. // 静态成员与类实例无关,因此不能用$this访问,直接使用类去调用
  10. self::$salary = $salary;
  11. }
  12. public static function staffSalary() {
  13. return '员工的工资:'.self::$salary;
  14. }
  15. }

实例化Staff类:

  1. $staff = new Staff('张三', 8899);
  2. // 使用类名访问静态属性
  3. echo Staff::$salary; // 8899
  4. // 使用类名访问静态方法
  5. echo Staff::staffSalary(); // 员工的工资:8899

四、类的继承(extends)

类的继承使用extends关键字,也就是对类的功能进行扩展。

  1. require 'Student.php';
  2. class Sub extends Student {
  3. // 类的继承一般有两个用处:
  4. // 1. 对父类方法进行重写;
  5. // 2. 对父类功能进行扩展。
  6. // 扩展一个属性,score:分数
  7. private $score;
  8. // 子类构造器,重写了父类的方法
  9. public function __construct($name, $gender, $age, $score)
  10. {
  11. // 调用父类成员
  12. parent::__construct($name, $gender, $age);
  13. $this->score = $score;
  14. }
  15. // 重写父类的getStuInfo()方法
  16. public function getStuInfo()
  17. {
  18. return parent::getStuInfo()."分数:{$this->score}";
  19. }
  20. // 增加一个新方法,判断学生成绩是否及格。
  21. public function isPass()
  22. {
  23. if ($this->score > 60) {
  24. return "该学生成绩已及格,分数为:{$this->score}";
  25. }
  26. }
  27. }
  28. $sub = new Sub('张三', '男', 16, 90);
  29. echo $sub->getStuInfo(); // 姓名:张三,性别:男,年龄:16岁。分数:90
  30. echo "<br>";
  31. echo $sub->isPass(); // 该学生成绩已及格,分数为:90

以上案例分别输出结果:

姓名:张三,性别:男,年龄:16岁。分数:90

该学生成绩已及格,分数为:90

五、Trait(代码复用)

Trait 是为类似 PHP 的单继承语言而准备的一种代码复用机制。Trait 为了减少单继承语言的限制,为了使开发者能复用某些方法。
可以把trait理解为一个公共方法集,它借用了class语法实现了一个轻量级的“类”,但它不是类,所以不能实例化。

  • trait 示例
  1. trait userInfo {
  2. public function getUserInfo () {
  3. return "This is userInfo " . $this->name;
  4. }
  5. }
  6. class User
  7. {
  8. // 使用关键字use引入需要使用的trait
  9. use userInfo;
  10. }
  • 优先级
  1. trait userInfo {
  2. public function getUserInfo () {
  3. return "This is userInfo " . $this->name;
  4. }
  5. }
  6. class UserBase
  7. {
  8. public $username;
  9. // 引用trait
  10. use userInfo;
  11. public function __construct($username)
  12. {
  13. $this->username = $username;
  14. }
  15. public function getUserInfo () {
  16. return "This is UserBase " . $this->name;
  17. }
  18. public function getUserName() {
  19. return "UserBase:".$this->username;
  20. }
  21. }

以上代码在trait中和UserBase类中都声明了一个getUserInfo()方法,当在getUserInfo()类中引入trait里面的方法之后我们创建类实例,然后调用getUserInfo()方法,发现调用的是UserBase类里面的getUserInfo()方法。

trait冲突解决办法

当我同时声明了两个trait中有两个相同的方法getUserInfo(),那么在类中访问的时候回报错,具体案例如下:

  1. trait user1 {
  2. public function getUserInfo () {
  3. return "This is user1 ";
  4. }
  5. }
  6. trait user2 {
  7. public function getUserInfo () {
  8. return "This is user2 ";
  9. }
  10. }
  11. class User {
  12. use user1;
  13. use user2;
  14. }

以上代码会报错:Trait method getUserInfo has not been applied,because there are collisions with other trait methods on User in E:\phpstudy_pro\WWW\phpcn\PHP\20210202\demo5.php on line 59

解决办法是:优先级与别名:

  1. trait user1 {
  2. public function getUserInfo () {
  3. return "This is user1 ";
  4. }
  5. }
  6. trait user2 {
  7. public function getUserInfo () {
  8. return "This is user2 ";
  9. }
  10. }
  11. class User {
  12. use user1, user2 {
  13. // 1.优先级
  14. user1::getUserInfo insteadof user2;
  15. // 2.别名
  16. user2::getUserInfo as user2GetUserInfo;
  17. }
  18. }
  19. echo (new User('张三'))->getUserInfo(); // This is user1
  20. echo (new User('张三'))->user2GetUserInfo(); // This is user2

当父类trait与当前子类中存在同名成员时,如何解决?

  1. class SubUser extends User
  2. {
  3. use user3;
  4. public function fun () {
  5. return __METHOD__;
  6. }
  7. }

此时的结果是:SubUser::fun,说明子类的优先级高于父类的。

如果在父类与子类之间加了一个trait里面的一个同名函数,此时的优先级是什么样呢?

  1. trait user3{
  2. public function fun () {
  3. return __METHOD__;
  4. }
  5. }
  6. class SubUser extends User
  7. {
  8. use user3;
  9. public function fun () {
  10. return __METHOD__;
  11. }
  12. }
  13. echo (new SubUser())->fun(); // SubUser::fun

如果此时子类SubUser中没有fun方法呢?

  1. trait user3{
  2. public function fun () {
  3. return __METHOD__;
  4. }
  5. }
  6. class SubUser extends User
  7. {
  8. use user3;
  9. }
  10. echo (new SubUser())->fun(); // user3::fun

此时的结果是:user3::fun

这时,我们可以得出这个优先级的结果:自己拥有的 > trait > 父类的。

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