php面向对象中子类中重载父类详解

因为在PHP中不能存在同名的函数,所以在同一个类中也就不能定义重名的方法,这里所说的重载是指在子类中可以定义和父类同名的方法从而覆盖从父类中继承过来的方法。

子类中重载父类的方法,实例代码如下:

  1. <?php
  2. class Person{
  3. public $name;
  4. public function __construct($name="" ){
  5. $this->name =$name;
  6. }
  7. public function say(){
  8. echo "我叫".$this->name ;
  9. }
  10. }
  11. ?>
  12. <?php
  13. class Student extends Person{
  14. public $name;
  15. public function __construct($name=""){
  16. $this->name =$name;
  17. }
  18. //这里定义了一个和父类中同名的方法,将父类中的说话方法覆盖并重写
  19. public function say(){
  20. echo "我叫".$this->name .",今年25岁了" ;
  21. }
  22. }
  23. ?>

重写方法与访问权限

子类中的覆盖方法不能使用比父类中被覆盖方法更严格的访问权限,如果父类中的方法的访问权限是protected,那么子类中重写的方法的权限就要是protected或者public; 如果父类中的方法是public,那么子类要重写的方法的权限就只能是public。也许这也就是为什么子类可以继承父类的私有成员,但却不能使用的原因吧。

重写时的参数数量

子类可以拥有与父类不同的参数数量,如下面的构造方法中,多添加了一个参数$age,实例代码如下:

  1. <?php
  2. class Student extends Person{
  3. public $name;
  4. public $age;
  5. public function __construct($name="",$age=25){
  6. $this->name =$name;
  7. $this->age =$age;
  8. }
  9. public function say(){
  10. echo "我叫".$this->name .",今年".$this->age."岁了" ;
  11. }
  12. }
  13. ?>

构造函数重写

上面提到的“重写时的参数数量”就已经实现了子类对父类的构造函数进行了重写,但这不是一种好的写法,如果仔细观察,你会发现,上面子类Student对父类Person构造函数的重写,其实就是在父类的构造函数的基础上多添加了一个参数,但是又把父类原有的参数照写一遍,因为父类Person的构造函数只有一个参数,所以我们照写一遍不觉得有什么麻烦,但是如果参数不止一个,而是几个或者更多,那么你就会发现它的繁琐之处,那么有没有办法可以简化这个问题呢?答案是肯定的,可通过使用"parent::方法名" 在子类的重载方法中调用父类中被它覆盖的方法,如使用"parent::__construct()"调用父类中被覆盖的构造方法,其它方法的类似,于是上面的代码可以简化为:

  1. <?php
  2. class Student extends Person{
  3. public $name;
  4. public $age;
  5. public function __construct($name="",$age=25){
  6. parent::__construct($name,$age);
  7. $this->age =$age;
  8. }
  9. public function say(){
  10. parent::say();
  11. echo ",今年".$this->age."岁了" ;
  12. }
  13. }
  14. ?>

下再看一个实例

PHP5重写方法

先设置一个父类,这个父类是 “Dog”类,这个类描述了dog的特性,Dog有2个眼睛,会跑,会叫。就这样描述先,我养了一直狗,是只小狗,符合Dog类的特性,但有所不同,我的小狗有名字,我的小狗太小了,不会大声的叫,只会哼哼,我们用继承的概念去实现这个设计,代码如下:

  1. <?
  2. // 狗有两只眼睛,会汪汪叫,会跑.
  3. class Dog {
  4. protected $eyeNumber =2; //属性
  5. //返回封装属性的方法.
  6. public function getEyeNumber(){
  7. return $this->eyeNumber;
  8. }
  9. //狗会叫
  10. public function yaff(){
  11. return "Dog yaff, wang ..wang ..";
  12. }
  13. //狗会跑
  14. public function run(){
  15. return "Dog run..running ...";
  16. }
  17. }
  18. $dog = new Dog();
  19. echo "dog have ".$dog->getEyeNumber()." eyes. <br>";
  20. echo $dog->yaff() ."<br>".$dog->run();
  21. echo "<br><br>";
  22. //这是我的小狗叫"狗狗",它很小.不会汪汪叫,只会哼哼哼..
  23. class MyDog extends Dog {
  24. private $name = "狗狗";
  25. public function getName(){
  26. return $this->name;
  27. }
  28. public function yaff(){
  29. return $this->name." yaff, heng...heng ..";
  30. }
  31. }
  32. $myDog = new MyDog();
  33. echo $myDog->getName()." have ".$myDog->getEyeNumber()." eyes. <br>";
  34. echo $myDog->yaff() ."<br>".$myDog->run();
  35. ?>
  36. //程序运行结果:
  37. //dog have 2 eyes.
  38. //Dog yaff, wang ..wang ..
  39. //Dog run..running ...
  40. //狗狗 have 2 eyes.
  41. //狗狗 yaff, heng...heng ..
  42. //Dog run..running ...

重写方法与访问权限

子类中的覆盖方法不能使用比父类中被覆盖方法更严格的访问权限,父类为public 子类为 private时,实例代码如下:

  1. <?
  2. // 简化dog类和mydog类,演示重写的访问权限.
  3. class Dog {
  4. protected $eyeNumber =2; //属性
  5. //返回封装属性的方法.
  6. public function getEyeNumber(){
  7. return $this->eyeNumber;
  8. }
  9. }
  10. class MyDog extends Dog {
  11. protected function getEyeNumber(){
  12. return $this->eyeNumber;
  13. }
  14. }
  15. /*
  16. class MyDog extends Dog {
  17. private function getEyeNumber(){
  18. return $this->eyeNumber;
  19. }
  20. }
  21. */
  22. ?>
  23. //程序运行结果:
  24. //Fatal error: Access level to MyDog::getEyeNumber() must be public (as in class Dog) in E:PHPProjectstest.php on line 15

父类为public子类为protected时,实例代码如下:

  1. <?php
  2. // 简化dog类和mydog类,演示重写的访问权限.
  3. class Dog {
  4. protected $eyeNumber =2; //属性
  5. //返回封装属性的方法.
  6. public function getEyeNumber(){
  7. return $this->eyeNumber;
  8. }
  9. }
  10. class MyDog extends Dog {
  11. private function getEyeNumber(){
  12. return $this->eyeNumber;
  13. }
  14. }
  15. ?>
  16. //程序运行结果:
  17. //Fatal error: Access level to MyDog::getEyeNumber() must be public (as in class Dog) in E:PHPProjectstest.php on line 15

重写时的参数数量

子类可以拥有与父类不同的参数数量,这点与java不同,PHP是弱类型语言,实例代码如下:

  1. <?
  2. // 简化dog类和mydog类,演示重写方法的参数.
  3. class Dog {
  4. protected $eyeNumber =2; //属性
  5. //返回封装属性的方法.
  6. public function getEyeNumber(){
  7. return $this->eyeNumber;
  8. }
  9. }
  10. class MyDog extends Dog {
  11. //重写的方法与父类的方法有不同的参数数量.
  12. public function getEyeNumber($eys){
  13. $this->eyeNumber = $eys;
  14. return $this->eyeNumber;
  15. }
  16. }
  17. $myDog = new MyDog();
  18. echo "my dog hava ".$myDog->getEyeNumber(3) ." eyes.";
  19. //啸天犬..哈..
  20. //下面这句会报一个丢失参数的错误.
  21. //echo "my dog hava ".$myDog->getEyeNumber() ." eyes.";
  22. ?>
  23. //程序运行结果:
  24. //my dog hava 3 eyes.

构造函数重写

下面这个例子中,父类和子类都有自己的构造函数,当子类被实例化时,子类的构造函数被调用,而父类的构造函数没有被调用,请对比第一节的构造函数继承,实例代码如下:

  1. <?
  2. //2-2 / extends1.php
  3. //构造函数继承的问题.
  4. class Animal{
  5. public $legNum = 0;
  6. public function __construct(){
  7. $this->legNum = 4;
  8. echo "I am an animal<br>";
  9. }
  10. }
  11. class Dog1 extends Animal {
  12. public function __construct(){
  13. $this->legNum = 4;
  14. echo "I am a Dog .<br>";
  15. }
  16. }
  17. $dog1 = new Dog1();
  18. echo "<br>";
  19. echo "legNum is ".$dog1->legNum;
  20. /*
  21. 实例化子类时.构造函数被调用了.
  22. */
  23. ?>
  24. //程序运行结果:
  25. //I am a Dog .
  26. //legNum is 4

注:这点和Java不同,在java中构造函数是不能被继承的,而且子类实例化时,子类的构造函数被调用,父类的构造函数也会调用.