面向过程和面向对象

1. 历史因素

  • 只要是高级编程语言,面向对象永远都是绕不开的话题。早期的编程都是为了追求速度,而没有考虑可理解性和可扩展性。现在我们考虑的更多是可维护性和重用性。
  • PHP2:PHP其实一开始也没考虑对象,他是PHP的创建者们后来才想要引进的,PHP起源于Rasmus Lerdorf用Perl开发的两个工具,这时候PHP是 Personal Homepage Tool的简写,意为“个人主页工具”,而FI就是 From Interpreter“表单解释器”。只是用来处理表单数据到数据库,简单的控制下流程。
  • PHP3:此时PHP还是没有加入对类的支持. 1997.8.27 加入的
  • PHP4:算是PHP比较重大的改变,此时PHP的大部分核心代码都被重写了。Zend引擎开始为PHP提供助力
  • PHP5:PHP开始拥抱未来,支持了面向对象的程序设计
  • PHP7:弱语言类型也可以声明变量的类型,效率也大大提升了

2. 面向过程

我们用编写的程序来完成一件事/一个功能,需要哪些功能就建立哪些函数。管理起来非常混乱

3. 面向对象

我们不在仅仅只是想着去完成这件事就好了,将需要完成的事情分配给对象,每个对象各司其职。对象是执行者,干事的还是函数。这样我们可以更好的描述在解决问题和完成这件事中的行为,明显更符合人的思维习惯,同时也大大提升了代码的重用性和扩展性。


对象基础

1. 类和对象

  • 类:人类、车、宠物,我们可以按照人的划分习惯,将某一些具有相同特性的都是抽象化,这就是类。这就像是一个集合的概念。
  • 对象:是类的实例,比如人有很多,有人叫张三有人叫李四,他可能就有唯一一张ID卡,我们根据某些特性将类中的集合分离成一个个,对象是个体的概念。

1.1 最简单的类和对象

  1. <?php
  2. // 如,我们可以编写出一个,最简单的类
  3. class ShopProduct
  4. {
  5. // 类体
  6. }
  7. // 对象
  8. $product1 = new ShopProduct();
  9. $product2 = new ShopProduct();
  10. // 我很好奇这样一个几乎为空的对象有什么
  11. var_dump($product1); // object(ShopProduct)[1]
  12. // 除了告诉我这个一个对象,和是谁创建的模板也没啥了,哈哈

1.2 设置属性

  1. <?php
  2. class ShopProduct
  3. {
  4. // 此时,我们设置了4个属性
  5. public $title = 'default product';
  6. public $producerMainName = 'main name';
  7. public $producerFirstName = 'first name';
  8. public $price = 0;
  9. }
  10. // 访问其中的 title 属性
  11. print ((new ShopProduct)->title) . '<br>'; // default product
  12. // 也可以设置 属性的值
  13. $product1 = new ShopProduct();
  14. $product1->title = 'My Antonia';
  15. var_dump($product1);
  16. /*
  17. object(ShopProduct)[2]
  18. public 'title' => string 'My Antonia' (length=10)
  19. public 'producerMainName' => string 'main name' (length=9)
  20. public 'producerFirstName' => string 'first name' (length=10)
  21. public 'price' => int 0
  22. */
  23. // 实际上PHP没有强制所有属性都必须在类中声明,我们也可以动态的给对象添加属性
  24. $product1->arbitaryAddition = 'treehouse';
  25. var_dump($product1);
  26. // 但这并不是一个好的习惯,我们几乎不用。动态添加的属性可能会遇到种种问题。
  27. /*
  28. object(ShopProduct)[1]
  29. public 'title' => string 'My Antonia' (length=10)
  30. public 'producerMainName' => string 'main name' (length=9)
  31. public 'producerFirstName' => string 'first name' (length=10)
  32. public 'price' => int 0
  33. public 'arbitaryAddition' => string 'treehouse' (length=9)
  34. */

1.3 设置方法

  1. <?php
  2. class ShopProduct
  3. {
  4. public $title = 'default product';
  5. public $producerMainName = 'main name';
  6. public $producerFirstName = 'first name';
  7. public $price = 0;
  8. // 这里我们并没有添加,访问权限符号,因为默认的就是 public
  9. function getProducer()
  10. {
  11. return $this->producerMainName . '_' . $this->producerFirstName;
  12. }
  13. }
  14. $product1 = new ShopProduct();
  15. echo $product1->getProducer() . '<br>'; // main name_first name

1.4 设置构造函数

  1. <?php
  2. class ShopProduct
  3. {
  4. public $title;
  5. public $producerMainName;
  6. public $producerFirstName;
  7. public $price = 0;
  8. /**
  9. * 我们添加构造方法,创建对象时构造方法会被自动调用。
  10. * PHP5之前,构造方法使用和类相同的名字,像是java一样。
  11. * 但现在我们一般, __construct()
  12. **/
  13. public function __construct($title, $firstName, $mianName, $price)
  14. {
  15. $this->title = $title;
  16. $this->producerFirstName = $firstName;
  17. $this->producerMainName = $mianName;
  18. $this->price = $price;
  19. }
  20. public function getProducer()
  21. {
  22. return $this->producerMainName . '_' . $this->producerFirstName;
  23. }
  24. }
  25. $procuct1 = new ShopProduct('My Antonia', 'Willa', 'Cather', 5.99);
  26. var_dump($procuct1);
  27. /*
  28. object(ShopProduct)[1]
  29. public 'title' => string 'My Antonia' (length=10)
  30. public 'producerMainName' => string 'Cather' (length=6)
  31. public 'producerFirstName' => string 'Willa' (length=5)
  32. public 'price' => float 5.99
  33. */

1.5 PHP中的基本数据类型

  • 数据类型:PHP中也有八大基本数据类型,我也已经实在是不想写了。权当复习
    • 布尔型 boolead is_bool()
    • 整形 integer is_integer()
    • 浮点型 float is_double()
    • 字符型 strting is_string()
    • 数组 array is_array()
    • 对象 object is_object()
    • 资源 resource is_resource()
    • 空类型 null is_null()

1.6 继承

  • 继承是一从一个基类获取到更多派生类的机制
  • 基类也叫做父类,继承基类的就是子类,子类就可以增加父类之外的功能,这就是扩展性
  1. <?php
  2. // 如果我们有两种产品,我们将所有的属性都设置在一个类中,会显得十分臃肿。如下
  3. class ShopProduct
  4. {
  5. public $numPages;
  6. public $playLength;
  7. public $title;
  8. public $producerMainName;
  9. public $producerFirstName;
  10. public $price;
  11. function __construct($title, $firstName, $mianName, $price, $numPages = 0, $playLength = 0)
  12. {
  13. $this->title = $title;
  14. $this->producerFirstName = $firstName;
  15. $this->producerMainName = $mianName;
  16. $this->price = $price;
  17. $this->numPages = $numPages;
  18. $this->playLength = $playLength;
  19. }
  20. function getNumberOfPages()
  21. {
  22. return $this->numPages;
  23. }
  24. function getPlayLength()
  25. {
  26. return $this->playLength;
  27. }
  28. function getProducer()
  29. {
  30. return $this->producerFirstName . $this->producerMainName;
  31. }
  32. }
  1. <?php
  2. // 如果分开变成两个类,就会发现解决了不存在的属性。但是大量的代码重复还是让人感觉不是很愉快
  3. class cdProduct
  4. {
  5. public $playLength;
  6. public $title;
  7. public $producerFirstName;
  8. public $producerMainName;
  9. public $price;
  10. function __construct($title, $firstName, $mianName, $price, $playLength)
  11. {
  12. $this->title = $title;
  13. $this->producerFirstName = $firstName;
  14. $this->producerMainName = $mianName;
  15. $this->price = $price;
  16. $this->playLength = $playLength;
  17. }
  18. function getPlayLength ()
  19. {
  20. return $this->playLength;
  21. }
  22. function getSummaryLine()
  23. {
  24. $base = "{$this->title} | {$this->producerMainName} , ";
  25. $base .= "{$this->producerFirstName} , ";
  26. $base .= ": playing time - {this->playLength}";
  27. return $base;
  28. }
  29. function getProducer()
  30. {
  31. return $this->producerFirstName . $this->producerMainName;
  32. }
  33. }
  34. class BookProduct
  35. {
  36. public $numPages;
  37. public $title;
  38. public $producerMainName;
  39. public $producerFirstName;
  40. public $price;
  41. function __construct($numPages, $title, $firstName, $mianName, $price)
  42. {
  43. $this->numPages = $numPages;
  44. $this->title = $title;
  45. $this->producerFirstName = $firstName;
  46. $this->producerMainName = $mianName;
  47. $this->price = $price;
  48. }
  49. function getNumberOfPages()
  50. {
  51. return $this->numPages;
  52. }
  53. function getSummaryLine()
  54. {
  55. $base = "{$this->title} | {$this->producerMainName} , ";
  56. $base .= "{$this->producerFirstName} , ";
  57. $base .= ": playing time - {this->playLength}";
  58. return $base;
  59. }
  60. function getProducer()
  61. {
  62. return $this->producerFirstName . $this->producerMainName;
  63. }
  64. }
  1. <?php
  2. // 使用继承 - 父类产品
  3. class ShopProduct
  4. {
  5. public $numPages;
  6. public $playLength;
  7. public $title;
  8. public $producerMainName;
  9. public $producerFirstName;
  10. public $prrice;
  11. function __construct($numPages = 0, $title, $playLength = 0, $firstNmae, $mianName, $price)
  12. {
  13. $this->title = $title;
  14. $this->numPages = $numPages;
  15. $this->producerFirstName = $firstNmae;
  16. $this->producerMainName = $mianName;
  17. $this->playLength = $playLength;
  18. $this->price = $price;
  19. }
  20. function getProducer()
  21. {
  22. return $this->producerFirstName . $this->producerMainName;
  23. }
  24. function getSummaryLine()
  25. {
  26. return $this->title . ':' .
  27. $this->producerMainName . ',' .
  28. $this->producerFirstName;
  29. }
  30. }
  31. // 子类-cd
  32. class CdProduct extends ShopProduct
  33. {
  34. function getPlayLength()
  35. {
  36. return $this->playLength;
  37. }
  38. function getSummaryLine()
  39. {
  40. return $this->title . ':' .
  41. $this->producerMainName . ',' .
  42. $this->producerFirstName . ',' .
  43. $this->playLength;
  44. }
  45. }
  46. // 子类书
  47. class BookProduct extends ShopProduct
  48. {
  49. function getNumberOfPages()
  50. {
  51. return $this->numPages;
  52. }
  53. function getSummaryLine()
  54. {
  55. return $this->title . ':' .
  56. $this->producerMainName . ',' .
  57. $this->producerFirstName . ',' .
  58. $this->numPages;
  59. }
  60. }
  61. // 两个子类都会继承父类中的公共部分
  • 在子类中定义构造方法时需要传递参数给父类的构造方法,否则你得到的可能是一个不完整的对象
  • 子类调用父类的方法,使用parent 关键字 parent::__construct();
  • 我们依照parent关键字去添加子类的构造函数,并且从新改造父类和子类。
    • 我们通常把子类会用到的相同的属性提取到父类
    • 子类再去创建自己独有的属性,因为子类也可以访问到父类的属性
  1. <?php
  2. class ShopProduct
  3. {
  4. public $title;
  5. public $producerMainName;
  6. public $producerFirstName;
  7. public $prrice;
  8. function __construct($title,$firstNmae, $mianName, $price)
  9. {
  10. $this->title = $title;
  11. $this->producerFirstName = $firstNmae;
  12. $this->producerMainName = $mianName;
  13. $this->price = $price;
  14. }
  15. function getProducer()
  16. {
  17. return $this->producerFirstName . $this->producerMainName;
  18. }
  19. function getSummaryLine()
  20. {
  21. return $this->title . ':' .
  22. $this->producerMainName . ',' .
  23. $this->producerFirstName;
  24. }
  25. }
  26. class CdProduct extends ShopProduct
  27. {
  28. public $playLength;
  29. function __construct($title,$firstNmae, $mianName, $price, $playLength)
  30. {
  31. parent::__construct($title,$firstNmae, $mianName, $price);
  32. $this->playLength = $playLength;
  33. }
  34. function getPlayLength()
  35. {
  36. return $this->playLength;
  37. }
  38. function getSummaryLine()
  39. {
  40. return $this->title . ':' .
  41. $this->producerMainName . ',' .
  42. $this->producerFirstName . ',' .
  43. $this->playLength;
  44. }
  45. }
  46. class BookProduct extends ShopProduct
  47. {
  48. public $numPages;
  49. function __construct($title,$firstNmae, $mianName, $price, $numPages)
  50. {
  51. parent::__construct($title,$firstNmae, $mianName, $price);
  52. $this->numPages = $numPages;
  53. }
  54. function getNumberOfPages()
  55. {
  56. return $this->numPages;
  57. }
  58. function getSummaryLine()
  59. {
  60. return $this->title . ':' .
  61. $this->producerMainName . ',' .
  62. $this->producerFirstName . ',' .
  63. $this->numPages;
  64. }
  65. }
  • 此时,结构清晰了很多,但我们还是发现,子类和父类还是有 getSummaryLine()这个方法
  • 重写这个方法是我们也 用上 parent 关键字
  1. <?php
  2. class ShopProduct
  3. {
  4. public $title;
  5. public $producerMainName;
  6. public $producerFirstName;
  7. public $prrice;
  8. function __construct($title, $firstNmae, $mianName, $price)
  9. {
  10. $this->title = $title;
  11. $this->producerFirstName = $firstNmae;
  12. $this->producerMainName = $mianName;
  13. $this->price = $price;
  14. }
  15. function getProducer()
  16. {
  17. return $this->producerFirstName . $this->producerMainName;
  18. }
  19. function getSummaryLine()
  20. {
  21. return $this->title . ':' .
  22. $this->producerMainName . ',' .
  23. $this->producerFirstName;
  24. }
  25. }
  26. class CdProduct extends ShopProduct
  27. {
  28. public $playLength;
  29. function __construct($title, $firstNmae, $mianName, $price, $playLength)
  30. {
  31. parent::__construct($title, $firstNmae, $mianName, $price);
  32. $this->playLength = $playLength;
  33. }
  34. function getPlayLength()
  35. {
  36. return $this->playLength;
  37. }
  38. function getSummaryLine()
  39. {
  40. $base = parent::getSummaryLine();
  41. return $base . 'playing time:' . $this->playLength;
  42. }
  43. }
  44. class BookProduct extends ShopProduct
  45. {
  46. public $numPages;
  47. function __construct($title, $firstNmae, $mianName, $price, $numPages)
  48. {
  49. parent::__construct($title, $firstNmae, $mianName, $price);
  50. $this->numPages = $numPages;
  51. }
  52. function getNumberOfPages()
  53. {
  54. return $this->numPages;
  55. }
  56. function getSummaryLine()
  57. {
  58. $base = parent::getSummaryLine();
  59. return $base . 'number of pages:' . $this->numPages;
  60. }
  61. }

1.7 类的访问管理

  • 三种基本的权限访问修饰符

    • public:公共的,任何地方都可以访问public修饰的属性和方法
    • protected:受保护的,只有当前类和子类才可以访问
    • private:私有的,只有当前类才可以访问,子类也不可以访问
  • 小技巧

    • private 、 protectedt 通常是用来保护用的,我们通常用 private 来修饰属性让外部无法去更改,从而达到保护的作用
    • 简而言之,有些类方法和类属性本身只为该类提供方法,不对外提供,我们就应该设置权限为 private 或者是protected的
  • 我们依照权限访问符,加入商品打折的属性,从写改写一下 父类和子类

  • 父类-商品类

    1. <?php
    2. class ShopProduct
    3. {
    4. // 私有化属性
    5. private $title;
    6. private $producerMainName;
    7. private $producerFirstName;
    8. private $discount = 1; // 1 就表示不打折
    9. protected $prrice;
    10. // 构造函数
    11. public function __construct($title, $firstNmae, $mianName, $price)
    12. {
    13. $this->title = $title;
    14. $this->producerFirstName = $firstNmae;
    15. $this->producerMainName = $mianName;
    16. $this->price = $price;
    17. }
    18. // 获取商品的 firstName
    19. public function getProducerFirstName()
    20. {
    21. return $this->producerFirstName;
    22. }
    23. // 获取商品的 mainName
    24. public function getProducerMainName()
    25. {
    26. return $this->producerMainName;
    27. }
    28. // 获取商品的title
    29. public function getTitle()
    30. {
    31. return $this->title;
    32. }
    33. // 获取商品的价格
    34. public function getPrice()
    35. {
    36. return $this->prrice;
    37. }
    38. // 获取折扣
    39. public function getDisCount()
    40. {
    41. return $this->discount;
    42. }
    43. // 设置折扣
    44. public function setDisCount($num)
    45. {
    46. $this->discount = $num;
    47. }
    48. // getProducer
    49. public function getProducer()
    50. {
    51. return $this->producerFirstName . $this->producerMainName;
    52. }
    53. // getSummaryLine
    54. public function getSummaryLine()
    55. {
    56. return $this->title . ':' .
    57. $this->producerMainName . ',' .
    58. $this->producerFirstName;
    59. }
    60. }
  • 子类-书

    1. <?php
    2. class BookProduct extends ShopProduct
    3. {
    4. private $numPages;
    5. function __construct($title, $firstNmae, $mianName, $price, $numPages)
    6. {
    7. parent::__construct($title, $firstNmae, $mianName, $price);
    8. $this->numPages = $numPages;
    9. }
    10. function getNumberOfPages()
    11. {
    12. return $this->numPages;
    13. }
    14. function getSummaryLine()
    15. {
    16. $base = parent::getSummaryLine();
    17. return $base . 'number of pages:' . $this->numPages;
    18. }
    19. }
  • 子类-cd

    1. <?php
    2. class CdProduct extends ShopProduct
    3. {
    4. private $playLength;
    5. function __construct($title, $firstNmae, $mianName, $price, $playLength)
    6. {
    7. parent::__construct($title, $firstNmae, $mianName, $price);
    8. $this->playLength = $playLength;
    9. }
    10. function getPlayLength()
    11. {
    12. return $this->playLength;
    13. }
    14. function getSummaryLine()
    15. {
    16. $base = parent::getSummaryLine();
    17. return $base . 'playing time:' . $this->playLength;
    18. }
    19. }

    2. 测试访问权限修饰符

    2.1 测试一 对象访问本类的非静态属性和非静态方法

    ```php <?php class Father { public $a = ‘a 属性’; protected $b = ‘b 属性’; private $c = ‘c 属性’;

    public function a() {

    1. echo "function a <br/>";

    }

    protected function b() {

    1. echo "function b <br/>";

    }

    private function c() {

    1. echo "function c <br/>";

    } }

$fa = new Father(); echo $fa->a; // a 属性 // echo $fa->b; // Fatal error: Uncaught Error: Cannot access protected property Father::$b // echo $fa->c; // Fatal error: Uncaught Error: Cannot access private property Father::$c

$fa->a(); // function a // $fa->b(); // Fatal error: Uncaught Error: Call to protected method Father::b() // $fa->c(); // Fatal error: Uncaught Error: Call to private method Father::c()

  1. <a name="ic3Vt"></a>
  2. #### 2.2 测试二 本类访问静态属性和静态方法
  3. ```php
  4. <?php
  5. class Father
  6. {
  7. public static $a = 'a 属性';
  8. protected static $b = 'b 属性';
  9. private static $c = 'c 属性';
  10. public static function a()
  11. {
  12. echo "function a <br/>";
  13. }
  14. protected static function b()
  15. {
  16. echo "function b <br/>";
  17. }
  18. private static function c()
  19. {
  20. echo "function c <br/>";
  21. }
  22. }
  23. echo Father::$a; // a 属性
  24. // echo Father::$b; // Fatal error: Uncaught Error: Cannot access protected property Father::$b
  25. // echo Father::$c; // Fatal error: Uncaught Error: Cannot access private property Father::$c
  26. Father::a(); // function a
  27. // Father::b(); // Uncaught Error: Call to protected method Father::b()
  28. // Father::c(); // Fatal error: Uncaught Error: Call to private method Father::c()

2.3 测试三 子类访问父类的属性和方法

  1. <?php
  2. //父类
  3. class Father
  4. {
  5. public $a = 'a 属性';
  6. protected $b = 'b 属性';
  7. private $c = 'c 属性';
  8. public function a()
  9. {
  10. echo "function a <br/>";
  11. }
  12. protected function b()
  13. {
  14. echo "function b <br/>";
  15. }
  16. private function c()
  17. {
  18. echo "function c <br/>";
  19. }
  20. }
  21. class Son extends Father
  22. {
  23. public function method_1()
  24. {
  25. echo parent::$a . '<br>';
  26. }
  27. public function method_2()
  28. {
  29. echo parent::$b . '<br>';
  30. }
  31. public function method_3()
  32. {
  33. echo parent::$c . '<br>';
  34. }
  35. public function method_4()
  36. {
  37. parent::a();
  38. }
  39. public function method_5()
  40. {
  41. parent::b();
  42. }
  43. public function method_6()
  44. {
  45. parent::c();
  46. }
  47. }
  48. $son = new Son();
  49. // $son->method_1(); // Fatal error: Uncaught Error: Access to undeclared static property: Father::$a
  50. // $son->method_2(); // Fatal error: Uncaught Error: Access to undeclared static property: Father::$b
  51. // $son->method_3(); // Fatal error: Uncaught Error: Cannot access private property Father::$c
  52. $son->method_4(); // function a
  53. $son->method_5(); // function b
  54. // $son->method_6(); // Fatal error: Uncaught Error: Call to private method Father::c() from context 'Son'


2.4 测试小结

  • 对象无论是访问本类的非静态的属性还是访问非静态的方法都只能访问 public ,protected和privated 都不行
    • 为什么PHP中,本类创建的对象连protected修饰的方法和属性都无法访问?
    • 这是我自己理解的问题!!!! 使用方式就像局部变量定义,但是超出了使用范围
  • 上一条对于静态修饰的方法和属性一样适用

  • 子类使用parent 关键字只能访问父类的 public 方法和 protected方法,并不能访问非静态的属性

    • parent :: 那么对于子类访问父类的静态属性呢?
      • public 和 protected 可以访问到
      • privated 访问不到
  1. <?php
  2. class Father
  3. {
  4. public $a = 'a 属性';
  5. protected $b = 'b 属性';
  6. private $c = 'c 属性';
  7. public function a()
  8. {
  9. echo "function a <br/>";
  10. }
  11. protected function b()
  12. {
  13. echo "function b <br/>";
  14. }
  15. private function c()
  16. {
  17. echo "function c <br/>";
  18. }
  19. }
  20. class Son extends Father
  21. {
  22. public function index()
  23. {
  24. $son = new Son();
  25. $son->b(); // al
  26. }
  27. }
  28. $son = new Son();
  29. $son->index(); // function b