在PHP里,什么是抽象类?

抽象类指的是不能被直接实例化的类,它专门用作其他类的基类,用于定义抽象方法(抽象方法指的是通过abstract修饰的方法)和具体方法(有实现的方法)。

抽象类必须用abstract来修饰!值得注意的是,如果一个类至少有一个抽象方法,那么这个类就是抽象类

比如我们准备一个抽象类People,由于每个人学习、放松、运动、恋爱的方法不同,所以我们可以抽象出四个方法。因为是抽象方法,所以在声明时需要使用abstract关键字来修饰,不需要“{}”来具体指定方法,而是换成“;”结束抽象方法。

<?php 
/* 1. 准备一个抽象类 */
abstract class People//2. 抽象类必须通过abstruct关键字来修饰
{
    // 3. 如果有一个抽象方法,那么这个类一定是抽象类,以下有4个抽象方法,都没有通过“{}”指明具体方法,而且通过“;”结束抽象语句
    abstract public function study();//学习
    abstract public function relax();//放松
    abstract public function sport();//运动
    abstract public function love();//恋爱       
}
?>

抽象类是为服务于子类而产生的,所以谈论抽象类就离不开继承这个环节。

1. 我们先讨论权限问题(指的是public、protected修饰抽象类时。注意,没有private修饰抽象类):

我们都知道,子类继承父类时,由于父类的访问权限不同,所以子类能够继承的数据是有差异的,具体情况如下:

关键字类内部访问子类访问外部访问
public√允许√ 允许√ 允许
protected√ 允许√ 允许× 不允许
private√ 允许× 不允许× 不允许

对于抽象类的继承,我们要求:子类实现方法的权限不能比抽象方法更严格!

比如People类是抽象类,子类是Programmar,抽象类People的抽象方法study()被public修饰,子类的study()就不能被protected修饰;如果抽象类People的抽象方法study()被protected修饰,那么子类的study()既可以使用public修饰又可以使用protected修饰。这个约束既来自于技术层面(避免运行时访问错误),又来自于默认的里氏替换原则(子类必须替换父类),所以请读者谨记这个契约。

下面,我们通过代码来描述这个约束:

<?php 
/* 1. 准备一个抽象类 */
abstract class People
{
    /* 抽象方法是服务于子类的,禁止private! */
    abstract public function study();//学习
    abstract public function relax();//放松
    abstract public function sport();//运动
    abstract protected function love();//恋爱 
}
/* 2.准备一个Programmar类 */
class Programmar extends People
{
    /* 必须全部重写父类抽象方法 */
    public function study()//由于抽象类的study()是public,所以子类就不能是protected!
    {
        echo '学算法';
    }
    public function relax()
    {
        echo '适当放松,保持健康心理';
    }
    public function sport()
    {
        echo '多运动,爱护身体';
    }
    protected function love()//有细节,由于love()是protected,子类可以是public,也可以是protected,毕竟有些爱不能说出
    {
        echo '恋爱,该谈就谈!';
    }
}
?>


2. 参数问题,如果抽象父类抽象方法有参数,子类继承的方法就必须存在这些参数,禁止额外参数

<?php 
/* 1. 准备一个抽象类 */
abstract class People
{
    /* 抽象方法是服务于子类的,禁止private! */
    abstract protected function love($who);//比如这里的love(),只能和一个人谈吧,所以指定一个参数 $who
}
/* 2.准备一个Programmar类 */
class Programmar extends People
{
    /* 必须全部重写父类抽象方法 */
    protected function love($who,$other)//有细节,明明抽象父类抽象方法love()只有一个参数,你这里有额外参数,那岂不是破坏约定,会报错!
    {
        echo '恋爱,该谈就谈!';
    }
}
?>


3. 重写完父类抽象方法后,子类可以自由添加自己的方法:

<?php 
/* 1. 准备一个抽象类 */
abstract class People
{
    /* 抽象方法是服务于子类的,禁止private! */
    abstract public function study();//学习
}
/* 2.准备一个Programmar类 */
class Programmar extends People
{
    /* 必须全部重写父类抽象方法 */
    public function study()//由于抽象类的study()是public,所以子类就不能是protected!
    {
        echo '学算法';
    }
    /* 重写玩父类的抽象方法后,子类允许存在自己的方法 */
    public function art()
    {
        echo '琴棋书画,样样精通!';
    }
    public function dream($aim)
    {
echo '我要实现'.$aim;
    }
}
?>


总结:抽象类必须要用abstract关键字修饰,一个类只要有一个抽象方法就被视为抽象类;抽象方法通过abstract关键字修饰,没有“{}”具体方法,通过“;”结束抽象方法;继承抽象父类,子类必须全部实现父类抽象方法,同时保持参数的一致性。

点赞(0)

C语言网提供由在职研发工程师或ACM蓝桥杯竞赛优秀选手录制的视频教程,并配有习题和答疑,点击了解:

一点编程也不会写的:零基础C语言学练课程

解决困扰你多年的C语言疑难杂症特性的C语言进阶课程

从零到写出一个爬虫的Python编程课程

只会语法写不出代码?手把手带你写100个编程真题的编程百练课程

信息学奥赛或C++选手的 必学C++课程

蓝桥杯ACM、信息学奥赛的必学课程:算法竞赛课入门课程

手把手讲解近五年真题的蓝桥杯辅导课程

Dotcpp在线编译      (登录可减少运行等待时间)