面向对象之继承

面向对象之继承

一、什么是继承

对象的继承是指从一个类派生出另外的一个类的过程,就像孩子是从父母那里继承品性一样。

  • 关键字 extends
  • PHP只能有一个父类
  • 关键词 instanceof 可以用来查看一个特别的对象是不是属于一种特定的类的类型
require 'demo.class.php';
$obj = new ChildClass();
if( $obj instanceof Demo ){
    $obj->test();
}

1、全部继承

子类继承(也就是具有)父类的全部属性和方法

class Person
{
    public $name;
    public $age;
    public $info;

    public function __construct($name,$age,$info)
    {
        $this->name = $name;
        $this->age = $age;
        $this->info = $info;
    }

    public function talk(){
        return '你好面试官,我叫' . $this->name . ',今年'.$this->age . ',特长:'. $this->info; 
    }
}

class Man extends Person
{

}

$jack = new Man('jack',18,'帅的令人发指');
echo $jack->talk();

2、部分继承

子类还可以添加自己的成员,从而可以保持和父类有所区别

class Man extends Person
{
    public function checkAge(){
        return $this->age>=18 ? '拉出去当壮丁' : '还是小鲜肉';
    }
}

$jack = new Man('jack',18,'帅的令人发指');
echo $jack->talk();
echo $jack->checkAge();

3、无限多子继承

class Man extends Person
{
    public function checkAge(){
        return $this->age>=18 ? '拉出去当壮丁' : '还是小鲜肉';
    }
}

class Women extends Person {

}

二、访问控制

封装 我们为什么要使用面向对象编程呢?既然只需要使用方法就可以写出复杂且实用的网站? OOP的真正价值在于封装,它的意义在于将相互关联的一组值和函数封装在一起,组成一个编程单元

封装的概念 : 通过修饰符 改变成员属性或者成员方法的访问权限,达到保护的作用。

修饰符 public protected private
本类内 Y Y Y
子类内 Y Y N
外部 Y N N

类的属性和成员方法在哪里可以用、可以被访问

class User extends Demo
{
    public $username = 'jack';
    protected $truename = '老聂';
    private $age = '18';

    public function printInfo(){
        echo $this->username; 
        echo $this->truename;
        echo $this->age;
    }

    private function secret(){
        echo "这是个秘密!";
    }
}
  • 一个公共的(Public)成员可以从任何一个地方访问:类本身内部,派生的子类和其他类。
  • 类的受保护的(protected)成员只能在类本身以及子类中访问。
  • 私有(private)的限制是最严格的,这些成员只能在声明它们的类中进行访问。私有的类成员不能被子类或者这些类的一个对象实例访问到。

聂哥友情备注:作为一个惯例,私有变量名通常以一个下划线开始。这在很多面向对象编程语言中都是这样做的,即便它并不是必须这样做

访问修饰符的范围

子类复写父类中的方法时,子类中的 访问修饰符的范围要大于等于 父类的【 继承只能发扬光大,至少保持不变。不可以丢失东西。

在UML中的体现

  • + 公共的
  • - 私有的
  • # 受保护的

三、继承中的构造方法和析构方法

在子类里父类的构造函数会不会执行,分两种情况:

  1. 如子类不定义构造函数 __construct(),则父类的构造函数默认会被继承下来,且会自动执行。
  2. 如子类定义了构造函数 __construct(),因为构造函数名也是__construct(),所以子类的构造函数实际上是覆盖(override)了父类的构造函数。这时执行的是该子类的构造函数
class Demo
{
    function __construct()
    {
        echo '正在进行构造...<br/>';
    }
    function test(){
        echo '这是什么地方<br/>';
    }
    function __destruct()
    {
        echo '正在进行析构...<br/>';
    }
}
class ChildClass extends Demo
{
    function __construct()
    {
       //如果要在子类里执行父类的构造函数
       //parent::__construct();
        echo '我是后代构造函数-正在进行构造...<br/>';
    }
}

注意 parent::__construct(); 语句不一定必须放在子类的构造函数中。放在子类的构造函数中仅仅保证了其在子类被实例化时自动执行。

四、重写

重载就是函数或者方法有相同的名称,但是参数列表不相同的情形,这样的同名不同参数的函数或者方法之间,互相称之为重载函数或者方法。PHP不支持,但可用构造方法实现。

重写又叫覆盖,就是将父类继承下来的属性或方法重新定义,只有保护的或公共的属性或方法能够被重写

1、重写一个方法,子类定义的方法必须和父类的方法具有完全相同的名称和参数数量

class Person
{
    public $name;
    public $age;
    public $info;

    public function __construct($name,$age,$info)
    {
        $this->name = $name;
        $this->age = $age;
        $this->info = $info;
    }

    public function talk($fuhao){
        return '你好面试官,我叫' . $this->name . ',今年'.$this->age . ',特长:'. $this->info; 
    }
}

class Man extends Person
{
    public function checkAge(){
        return $this->age>=18 ? '拉出去当壮丁' : '还是小鲜肉';
    }

    public function talk(){

    }
}

2、PHP5.3+ 方法重写必须要相同个数的参数,如果非多个参数,这时要给其他参数设置默认值

class Person
{
    public $name;
    public $age;
    public $info;

    public function __construct($name,$age,$info)
    {
        $this->name = $name;
        $this->age = $age;
        $this->info = $info;
    }

    private function talk($fuhao){
        return '你好面试官,我叫' . $this->name . ',今年'.$this->age . ',特长:'. $this->info; 
    }
}
class Man extends Person
{
    public function checkAge(){
        return $this->age>=18 ? '拉出去当壮丁' : '还是小鲜肉';
    }

    public function talk($fuhao='没办法,我是来充数的'){

    }
}

3、私有属性或私有方法的重写问题

  1. 私有属性和方法不能覆盖,但其实子类可以定义跟父类私有的同名属性或方法,只是当做一个自身的新属性或方法来看待而已

参数必须保持一致(PHP5.4前)

class A
{
    private $name = '山炮';
    public function getName()
    {
        return $this->name;
    }
}
class B extends A
{
    private $name = '二货';

    public function getTest()
    {
        return $this->getName().$this->name;
    }
}
$b = new B;
echo $b->getTest();//山炮二货

3.2 访问私有属性 类中的私有属性或者方法是不能被继承的,但是当一个父类A中的方法FunA,调用了父类A中的Private私有属性或着方法的时,这个FunA在被继承以后,将能继续通过$this访问父类A中的Private私有属性或者方法,无论继承子类中对父类A中的私有属性或方法如何重新实现,直到FunA在继承子类中被重写

class A
{
    private $name = '山炮';
    public function getName()
    {
        return $this->name;
    }
}
class B extends A
{
    public $name = '二货';

}
$b = new B;
echo $b->name; //二货
echo $b->getName(); //山炮

4、构造方法重写问题,比较宽松,重写的时候参数可以不一致。

class Person
{
    public $name;
    public $age;
    public $info;

    public function __construct($name,$age,$info)
    {
        $this->name = $name;
        $this->age = $age;
        $this->info = $info;
    }

    private function talk($fuhao,$cans=''){
        return '你好面试官,我叫' . $this->name . ',今年'.$this->age . ',特长:'. $this->info; 
    }
}

class Man extends Person
{
    public function __construct()
    {
        echo '我的方法没有参数';
    }
}

$jack = new Man();

5、非完全重写

class Person
{
    public $name;
    public $age;

    public function __construct($name,$age)
    {
        $this->name = $name;
        $this->age = $age;
    }

    public function talk(){
        return '你好面试官,我叫' . $this->name . ',今年'.$this->age; 
    }
}

class Man extends Person
{
    public $info;
    public function __construct($name,$age,$info)
    {
        parent::__construct($name,$age);
        $this->info = $info;
    }

    public function talk(){
        return '我先敲门!'.parent::talk().',特长:'.$this->info;
    }
}

$jack = new Man('jack',18,"帅的令人发指");

echo $jack->talk();

五、不允许继承或重写 final

1.类里绝大部分方法,都是可以重写的。唯一的例外就是被定义了FINAL的方法:
final function myFunc(){

}
  • 属性不能被定义为 final,只有类和方法才能被定义为 final。
  • final关键字应该放在其他修饰符protect/public/private/static之前。
  • 定义为final的方法不能被任何子类所重写。
  • 类也可以声明为final,这意味着它不能被扩展。
2. 不能继承的类
final A{

}




posted @ 2021-09-05 20:08  成文的博客  阅读(272)  评论(0编辑  收藏  举报