Blogger Information
Blog 29
fans 0
comment 0
visits 11068
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
OOP 面向对象编程(1):1,类与对象、oop封装性、构造器 2,属性重载与方法重载 3,类的继承与功能扩展 4,类的原生自动加载
尹辉
Original
540 people have browsed it

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, '法系');
Correcting teacher:PHPzPHPz

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