博客列表 >OOP 面向对象编程(1):1,类与对象、oop封装性、构造器 2,属性重载与方法重载 3,类的继承与功能扩展 4,类的原生自动加载

OOP 面向对象编程(1):1,类与对象、oop封装性、构造器 2,属性重载与方法重载 3,类的继承与功能扩展 4,类的原生自动加载

尹辉
尹辉原创
2023年04月23日 19:07:51541浏览

4.8 OOP 面向对象编程

面向对象就是把生活中要解决的问题都用对象的方式进行存储:把所有的数据用属性、方法表现出来。对象之间的互动是通过方法的调用完成互动

4.8.1 类 class

  • 物以类聚,把具有相似特性的对象对垒到一个类中,类定义了这些相似对象拥有的相同的属性和方法
  • 类是相似对象的描述,成为类的定义,是该类对象的蓝图或者原型
  • 类的定义以关键字class开始,后面跟着这个类的名称。类的命名通常每个单词的第一个字母大写,以中括号开始和结束
  • 类的属性和方法统称为类成员
  1. class User
  2. {
  3. // 成员属性
  4. public $name;
  5. private $salary;
  6. protected $age;
  7. public function __construct($salary, $age)
  8. {
  9. // $this代表本对象
  10. $this->salary = $salary;
  11. $this->age = $age;
  12. }
  13. // 成员方法
  14. public function salary()
  15. {
  16. return $this->salary;
  17. }
  18. }

4.8.2 对象 object

  • 类的实例化:通过类定义创建一个类的对象
  • 对象:一个类的实例(Instance)

  • 类的实例化为对象时使用关键字new,new之后紧跟类的名称和一对圆括号

  • 类的定义属性值都是空或默认值,而对象的属性都有具体的值
  • 对象中得成员属性和方法可以通过 -> 符号来访问
  1. $name = '灭绝';
  2. $salary = 20000;
  3. $age = 18;
  4. // new 实例化 得到对象引用
  5. $mj = new User($salary, $age);
  6. // 访问对象的属性和方法
  7. $mj->name = $name;
  8. echo $mj->name; // 灭绝
  9. echo $mj->salary(); // 20000

4.8.3 对象的组成

  • 属性:用来描述对象的特定的值(组成元素),是对象的数据模型,用于描述对象的数据,也成为对象的成员变量
  • 方法:定义对象的行为,是对象的行为模型,用于描述对象能够做什么事情,称为对象的成员方法

4.8.4 对象的特点

  • 每一个对象都是独一无二的
  • 对象是一个特定的事物,他的职能是完成特定功能
  • 对象是可以重复使用,属性和方法的复用。(变量是实现数据的复用,函数是实现了代码块的复用)

4.8.5 访问控制

对象的属性和方法有三种访问权限:

  • public是公有的类成员,可以在任何地方被访问,可以被类以及子类或者对象都可以访问

    1. class User1
    2. {
    3. public $name;
    4. public function sayHello()
    5. {
    6. echo "Hello " . $this->name;
    7. }
    8. }
    9. $mj = new User1();
    10. $mj->name = '灭绝';
    11. echo $mj->name; // 灭绝
    12. echo $mj->sayHello(); //Hello 灭绝

    注意:尽量不要使用公共属性,因为直接访问公共属性不能强制性地检验数据有效性。例如,无法阻止用户给 name 这样赋值:$mj->name = ‘12345’;,解决方法:将属性设为私有属性,然后定义公共方法来调用是由属性。

  • private私有的类成员,只能被自身访问,不能被子类继承,也不能被对象访问,只能在自身通过封装让外界访问(例如在类里面定义一个公开方法来调用私有属性);

    1. class User
    2. {
    3. private $name;
    4. public function setName($name)
    5. {
    6. if ($this->validateName($name)){
    7. $this->name = $name;
    8. } else {
    9. echo "name 格式有误!";
    10. }
    11. }
    12. public function getName(){
    13. echo $this->name;
    14. }
    15. // 数据验证方法,仅对象内部可见,外部无法访问
    16. private function validateName($name){
    17. if ($name == '' || is_numeric($name)){
    18. return false;
    19. } else if (strlen($name) < 2 || strlen($name) > 8){
    20. return false;
    21. } else {
    22. return true;
    23. }
    24. }
    25. }
    26. $mj = new User();
    27. $mj->setName('灭绝');
    28. $mj->getName(); // 灭绝
  • protected 受保护的类成员,与 private 类似,区别是可以被子类继承,可以被其自身以及继承的子类访问,但是不能被对象访问,只能通过封装的方式让对象访问

4.8.6 构造方法

构造方法可以在对象实例化时自动运行,作用是:1,创建实例的初始化状态;2,可以给私有/受保护的属性初始化赋值。

构造方法必须是公共方法(public)。

定义构造方法关键字:__construct

  1. class User
  2. {
  3. // 成员属性
  4. public $name;
  5. private $salary;
  6. protected $age;
  7. public function __construct($salary, $age)
  8. {
  9. // $this代表本对象
  10. $this->salary = $salary;
  11. $this->age = $age;
  12. }
  13. // 成员方法
  14. public function salary()
  15. {
  16. return $this->salary;
  17. }
  18. }
  19. // 实例化时自动调用构造方法,将传入的参数赋值给属性 $salary, $age
  20. $mj = new User($salary, $age);
  21. // 属性 $name 没有在构造方法中赋值,需要手动赋值
  22. $mj->name = $name;

4.8.7 对象的继承

继承的好处:

  • 父类里面定义的类成员可以不用在子类中重复定义,节约了编程的时间和代价;
  • 同一个父类的子类拥有相同的父类定义的类成员,因此外部代码调用他们的时候可以一视同仁;
  • 子类可以修改和调用父类定义的类成员我们称为重写(Overwrite), 一旦子类修改了,就按照子类修改之后的功能执行;

子类:

  • 子类可以通过$this访问父类的属性
  • 子类的对象可以直接调用父类的方法和属性
  • PHP的单继承特性:类不允许同时继承多个父类(extends后面只能跟一个父类名称)
  • 子类可以扩展自己的属性和方法
  • 通过 extends 关键字实现类的继承
  1. // 父类
  2. class Product
  3. {
  4. public $name;
  5. protected $price;
  6. protected $num;
  7. public function __construct($name, $price, $num)
  8. {
  9. $this->name = $name;
  10. $this->price = $price;
  11. $this->num = $num;
  12. }
  13. // 普通方法
  14. public function show()
  15. {
  16. // 特殊的对象引用 完成对象成员间的互相访问
  17. // 注意:界定符结尾标记必须顶行写,前面不能有任何输出,否则出错!
  18. // 界定符结尾标记后面也不能有注释
  19. return <<<SHOW
  20. 1. 品名:$this->name
  21. 2. 价格:$this->price
  22. 3. 数量:$this->num
  23. SHOW;
  24. }
  25. }
  26. // 子类
  27. class Son extends Product
  28. {
  29. // 扩展
  30. public $brand;
  31. // overwrite 重写
  32. public function __construct($name, $price, $num, $brand)
  33. {
  34. // parent:: 调用父类成员
  35. parent::__construct($name, $price, $num);
  36. $this->brand = $brand;
  37. }
  38. // 重写show方法
  39. public function show()
  40. {
  41. return <<<SHOW
  42. 1. 品名:$this->name
  43. 2. 价格:$this->price
  44. 3. 数量:$this->num
  45. 4. 品牌:$this->brand
  46. SHOW;
  47. }
  48. // 功能扩展
  49. public function total()
  50. {
  51. return "$this->name,数量为{$this->num},总计" . ($this->price * $this->num) . '元';
  52. }
  53. }
  54. // 子类实例化及调用成员
  55. $son1 = new Son('四件套', 289, 400, '法系');
  56. echo $son1->brand; // 法系
  57. echo $son1->show(); // 1. 品名:四件套 2. 价格:289 3. 数量:400 4. 品牌:法系
  58. echo $son1->total(); // 四件套,数量为400,总计115600元

4.8.8 属性重载和方法重载

  • PHP所提供的”重载”(overloading)是指动态地”创建”类属性和方法。我们是通过魔术方法(magic methods)来实现的。
  • 当调用当前环境下未定义或不可访问的类属性或方法时,重载方法会被调用
  • 所有的重载方法都必须被声明为 public
  • 注意: PHP中的”重载”与其它绝大多数面向对象语言不同。传统的”重载”是用于提供多个同名的类方法,但各方法的参数类型和个数不同。
  1. class View
  2. {
  3. /**
  4. * 模板变量
  5. */
  6. protected $data = [];
  7. // !当访问当前环境下未定义或不可访问的类属性时 ,重载方法__get会被调用。
  8. public function __get($name)
  9. {
  10. return $this->data[$name];
  11. }
  12. // !当给当前环境下未定义或不可访问的类属性赋值时 ,重载方法__set会被调用。
  13. public function __set($name, $value)
  14. {
  15. $this->data[$name] = $value;
  16. }
  17. // 自定义的赋值方法优先级大于 __set
  18. public function assign($name, $value = null)
  19. {
  20. if (is_array($name)) {
  21. // array_merge() 将一个或多个数组中的值附加在前一个数组的后面。返回作为结果的数组
  22. $this->data = array_merge($this->data, $name);
  23. } else {
  24. $this->data[$name] = $value;
  25. }
  26. return $this;
  27. }
  28. // !当访问当前环境下未定义或不可访问的类普通方法时 ,重载方法__call会被调用。
  29. public function __call($name, $args)
  30. {
  31. if ($name == 'show') {
  32. var_dump($this->data);
  33. } else if ($name == 'sum') {
  34. return array_sum($args);
  35. } else {
  36. echo '没有这个方法';
  37. }
  38. }
  39. }
  40. $v = new View;
  41. // 调用 __set 方法,给未定义属性赋值
  42. $v->username = 'peter';
  43. // 调用 __get 方法,访问未定义属性
  44. echo $v->username; // peter
  45. // 自定义的赋值方法优先级大于 __set
  46. $v->assign('username', 'admin');
  47. echo $v->username; // admin
  48. // 调用 __call 方法,访问未定义方法
  49. $v->hello(); // 没有这个方法
  50. // show()、sum() 方法不可以直接访问,通过 __call 方法访问
  51. $v->show(); // array(1) { ["username"]=> string(5) "admin" }
  52. echo $v->sum(10, 20, 60); // 90
  53. // 通过回调方法访问 __call 方法
  54. echo call_user_func([$v, 'sum'], 10, 20, 40); // 70
  55. echo call_user_func_array([$v, 'sum'], [10, 20, 80]); // 110

4.8.9 类的自动加载器

定义类加载器文件 autoload.php

  1. // autoload.php
  2. spl_autoload_register(function ($className) {
  3. $classFile = __DIR__ . DS . 'class' . DS . $className . '.php';
  4. if (is_file($classFile) && file_exists($classFile)) require $classFile;
  5. });

在页面引入加载器,不用一个一个 require 所需的 class 文件

  1. const DS = DIRECTORY_SEPARATOR;
  2. require __DIR__ . DS . 'autoload.php';
  3. // 接下来用到的类都会自动加载
  4. $mj = new User($salary, $age);
  5. $i = new Product('iphone 12 promax', 6000, 12);
  6. $son1 = new Son('四件套', 289, 400, '法系');
声明:本文内容转载自脚本之家,由网友自发贡献,版权归原作者所有,如您发现涉嫌抄袭侵权,请联系admin@php.cn 核实处理。
全部评论
文明上网理性发言,请遵守新闻评论服务协议