抽象类与接口相似,都是一种比较特殊的类。抽象类是一种特殊的类,而接口也是一种特殊的抽象类。它们通常配合面向对象的多态性一起使用。虽然声明和使用都比较容易,但它们的作用在理解上会困难一点。

①抽象类

在OOP语言中,一个类可以有一个或多个子类,而每个类都有至少一个公有方法作为外部代码访问它的接口。而抽象方法就是为了方便继承而引入的。本节中先来介绍一下抽象类和抽象方法的声明,然后再说明其用途。在声明抽象类之前,我们先了解一下什么是抽象方法。抽象方法就是没有方法体的方法,所谓没有方法体是指在方法声明时没有花括号及其中的内容,而是在声明方法时直接在方法名后加上分号结束。另外在声明抽象方法时,还要使用关键字abstract来修饰。声明抽象方法的格式如下所示:

abstract function fun1(); //不能有花括号,就更不能有方法体中的内容了
abstract function fun2(); //直接在方法名的括号后面加上分号结束,还要使用abstract修饰

只要在声明类时有一个方法时抽象方法,那么这个类就是抽象类,抽象类也要使用abstract关键字来修饰。在抽象类中可以有不是抽象的成员方法和成员属性,但访问权限不能使用private关键字修饰为私有的。下面的例子在Person类中声明了两个抽象方法say()和eat(),则Person类就是一个抽象类,需要使用abstract标识。代码如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php
    abstract class Person{
        protected $name;
        protected $country;
 
        function __construct($name="",$country="china"){
            $this ->name = $name;
            $this ->country = $country;
        }
 
        abstract function say();
        abstract function eat();
 
        function run(){
            echo "使用两条腿走路<br>";
        }
    }
?>

在上例中声明了一个抽象类Person,在这个类中定义了两个成员属性、一个构造方法和两个抽象方法,还有一个是非抽象的方法。抽象类就像是一个“半成品”的类,在抽象类中有没有被实现的抽象方法,所以抽象类是不能被实例化的,即创建不了对象,也就不能直接使用它。既然抽象类是一个“半成品”的类,那么使用抽象类有什么作用呢?使用抽象类就包含了继承关系,它是为它的子类定义公共接口,将它的操作(可能是部分,也可能是全部)交给子类去实现。就是将抽象类作为子类重载的模板使用,定义抽象类就相当于定义了一种规范,这种规范要求子类去遵守。当子类继承抽象类以后,就必须把抽象类中的抽象方法按照子类自己的需要去实现。子类必须把父类中的抽象方法全部都实现,否则子类中还存在抽象方法,所以还是抽象类,也不能实例化对象。在下例中声明了两个类,分别实现上例中声明的抽象类Person。代码如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<?php
    class ChineseMan extends Person{
 
        function say(){
            echo $this ->name."是".$this->country."人,讲汉语<br>";   
        }
 
        function eat(){
            echo $this ->name."使用筷子吃饭<br>";
        }
    }
 
        class Americans extends Person{
 
        function say(){
            echo $this ->name."是".$this->country."人,讲英语<br>";   
        }
 
        function eat(){
            echo $this ->name."使用刀子和叉子吃饭<br>";
        }
    }
 
    $chianeseMan = new ChineseMan("高洛峰""中国");
    $americans = new Americans ("alex","美国");
 
    $chineseMan ->say();
    $chineseMan ->eat();
 
    $americans ->say();
    $americans ->eat();
?>

在上例中声明了两个类去继承抽象类Person,并将Person类中的抽象方法按各自的需求分别实现,这样两个子类就都可以创建对象了。抽象类Person就可以看成是一个模板,类中的抽象方法自己不去实现,只是规范了子类中必须要有父类中声明的抽象方法,而且要按照自己的特点实现抽象方法的内容。

②接口技术

因为PHP只支持单继承,也就是说每个类只能继承一个父类。当声明的新类继承抽象类实现模板以后,它就不能再有其他父类了。为了解决这个问题,PHP引入了接口。接口是一种特殊的抽象类,而抽象类又是一种特殊的类。如果抽象类中的所有方法都是抽象方法,我们就可以换另外一种声明方式,使用“接口”技术。接口中声明的方法必须都是抽象方法,另外不能再接口中声明变量,只能使用const关键字声明为常量的成员属性,而且接口中所有成员都必须有public的访问权限。类的声明是使用“class”关键字标识的,而接口的声明则是使用“interface”关键字标识的。声明接口的格式如下所示:

1
2
3
4
5
6
<?php
interface 接口名称{ //使用interface关键字声明接口
常量成员 //接口中的成员属性只能是常量,不能是变量
抽象方法 //接口中的所有方法必须是抽象方法,不能有非抽象的方法存在
}
?>

接口中的所有方法都要求是抽象方法,所以就不需要在方法前使用abstract关键字标识了。而且在接口中也不需要显式地使用public访问权限进行修饰,因为默认权限就是public的,也只能是公有的。另外接口和抽象类一样也不能实例化对象,它是一种更严格的规范,也需要通过子类来实现。但可以直接使用接口名称在接口外面去获取常量成员的值。一个接口的声明例子,代码如下所示:

1
2
3
4
5
6
7
<?php
interface one{
const CONSTANT = 'CONSTANT value';
function fun1();
function fun2();
}
?>

也可以使用extends关键字让一个接口去继承另一个接口,实现接口之间的扩展。在下面的例子中声明一个Two接口继承了上例中的One接口。代码如下所示:

1
2
3
4
5
6
<?php
interface Two extends one{
function fun3();
function fun4();
}
?>

如果需要使用接口中的成员,则需要通过子类去实现接口中的全部抽象方法,然后创建子类的对象去调用在子类中实现后的方法。但通过类去继承接口时需要使用implements关键字来实现,而并不是使用extends关键字完成。如果需要使用抽象类去实现接口中的部分方法,也需要使用implements关键字实现。在下面的例子中声明一个抽象类Three去实现One接口中的部分方法,但要想实例化对象,这个抽象类还需要有子类把它所有的抽象方法都实现才行。声明一个Four类去实现One接口中全部方法。代码如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?php
interface one{
const CONSTANT = 'CONSTANT value';
function fun1();
function fun2();
}
 
//声明一个抽象类去实现接口One中的第二个方法
abstract class Three implements One{ //只实现接口中的一个抽象方法
function fun2(){
//具体的实现内容由子类自己决定
}
}
 
//声明一个类实现接口One中的全部抽象方法
class Four implements One{
function fun1(){
//具体的实现内容由子类自己决定
}
 
function fun2(){
//具体的实现内容由子类自己决定
}
}
 
?>

PHP是单继承的,一个类只能有一个父类,但是一个类可以实现多个接口。将要实现的多个接口之间使用逗号分隔开,而且在子类中药将所有接口中的抽象方法全部实现才可以创建对象。就相当于一个类要遵守多个规范,就像我们不仅要遵守国家的法律,如果是在学校,还需要遵守学校的校规一样。实现多个接口的格式如下所示:

class 类名 implements 接口一,接口二,……接口n{
实现所有接口中的抽象方法
}

实现多个接口是使用“implements”关键字,同时还可以使用“extends”关键字继承一个类。即在继承类的同时实现多个接口,但一定更要先使用extends继承一个类,再去使用inplements实现多个接口。使用格式如下所示:

class 类名 extends 父类名 implements 接口一,接口二,……接口n{
实现所有接口中的抽象方法
}

除了上述的一些应用外,还有很多地方可以使用使用接口,例如对于一些已经开发好的系统,在结构上进行较大的调整已经不太现实,这时可以通过自定义一些接口并追加相应的实现来完成功能结构的扩展。

 

>> 本文固定链接: http://php.ncong.com/php_course/oop/abstract.html

>> 转载请注明: 恩聪php 2014年07月25日 于 恩聪PHP学习教程 发表

PHP的抽象类和接口的更多相关文章

  1. 抽象类 VS 接口

    引言 接口和抽象类是面向对象编程(OOP, Object Oriented programming)中两个绕不开的概念,二者相似而又有所不同.接下来,我们来了解二者的概念并比较它们的异同. 什么是抽象 ...

  2. java抽象类和接口

    面向对象设计过程中重要的一点是如何进行抽象,即把"问题空间"中的元素与"方案空间"中的元素建立理想的一对一的映射关系.抽象类和接口便是抽象过程中的产物.     ...

  3. php中抽象类与接口的概念以及区别

    php里面的接口类,抽象类到底有什么用呢? 刚接触php的时候,觉得这个东西没什么用,其实这些东西还是有一定的作用的,下面我就简单的说说. 1.php 接口类:interface 其实他们的作用很简单 ...

  4. Java 抽象类与接口

    接口和内部类为我们提供了一种将接口与实现分离的更加结构化的方法. 抽象类与接口是 Java 语言中对抽象概念进行定义的两种机制,正是由于他们的存在才赋予 Java 强大的面向对象的能力.他们两者之间对 ...

  5. 浅谈我对C#中抽象类与接口的理解

    C#中的抽象类与接口有些相似,初学者很容易混淆,今天就让我来谈谈对二者的理解. 首先我们得明确二者的含义,分述如下: 如果一个类不与具体的事物相联系,而只是表达一种抽象的概念,仅仅是作为其派生类的一个 ...

  6. Atitit 深入理解抽象类与接口 attilax总结

    Atitit 深入理解抽象类与接口 attilax总结 1.1. 主要区别接口侧重于动作抽象..抽象类是属性名词抽象..1 1.2. 抽象层次类>>抽象类>>接口1 1.3. ...

  7. luogg_java学习_07_抽象类_接口_多态学习总结

    这篇博客总结了半天,希望自己以后返回来看的时候理解更深刻,也希望可以起到帮助初学者的作用. 转载请注明 出自 : luogg的博客园 , 抽象 一种专门用来做父类,被继承的. (模板) 格式: abs ...

  8. PHP中抽象类,接口定义

    这里先介绍接口,因为在我最近看的好几本php工具书中都没有提到抽象类. 本人也觉得,在理解了接口后抽象类也非常好理解. 例子代码随便写了一下.例子代码是很ok的,测试过了不会报错,懒得看代码的筒靴们看 ...

  9. 0026 Java学习笔记-面向对象-抽象类、接口

    抽象方法与抽象类 抽象方法用abstract修饰,没有方法体部分,连花括号都不能有: 抽象方法和抽象类都用abstract修饰 包含抽象方法的类一定是抽象类:但不包含抽象方法的类也可以是抽象类 不能创 ...

  10. Java抽象类与接口的区别

    很多常见的面试题都会出诸如抽象类和接口有什么区别,什么情况下会使用抽象类和什么情况你会使用接口这样的问题.本文我们将仔细讨论这些话题. 在讨论它们之间的不同点之前,我们先看看抽象类.接口各自的特性. ...

随机推荐

  1. 14.4.4 Redo Log Buffer

    14.4.4 Redo Log Buffer redo log buffer 是内存区域持有数据被写入到redo log. Redo log buffer size 是通过 innodb_log_bu ...

  2. SSE及相关技术(web sockets, long polling等)

    server-sent events--One Way Messaging 允许网页获得来自服务器的更新,并且自动更新 Server-Sent Events: allow a web page to ...

  3. HDOJ 1018 Big Number(大数位数公式)

    Problem Description In many applications very large integers numbers are required. Some of these app ...

  4. 《Linear Algebra and Its Applications》-chaper2-矩阵代数中的基本性质

    之前我们曾经提及,完成了线性方程组-向量方程-矩阵方程的等价转化之后,我们对于现实问题中的线性方程组,只需将其转移到矩阵(向量)方程,然后利用矩阵代数中的各种方法和性质进行计算或者化简即可,而下面我们 ...

  5. yum nfs

    linux下3大文件共享方法 1.NFS NFS服务器配置 编辑/etc/exports,在文件中列出,要共享的目录.书写规则是:共享目录主机(参数).并且每条规则占据一行.例如: /mnt/mp3 ...

  6. android 反纠结app开发: 在线程中更新view

    大体上想实现一个思路: 对一个view 的内容进行不停地变化, 通过按钮停止这种变化,以达到随机选择的目的. 开发过程中 使用textview 模拟,  建立线程 mythread = new Thr ...

  7. C++标准库之 Lower_Bound, upper_Bound

    关于二分查找,这绝对是最简单却又最难的实现了,其各种版本号能够參见http://blog.csdn.net/xuqingict/article/details/17335833 在C++的标准库中,便 ...

  8. Brunch:快捷的HTML5构建工具

    Brunch,一个超快的HTML5构建工具.它可以(官方介绍): 编译你的脚本,模板,样式,链接它们, 将脚本和模板封装进common.js/AMD模块里,链接脚本和样式, 为链接文件生成源地图,复制 ...

  9. Linux Mysql如何移动MySQL数据库目录位置

      假如要把目录移到/home/data下需要进行下面几步: 1.home目录下建立data目录 cd /home mkdir data 2.把MySQL服务进程停掉: mysqladmin -u r ...

  10. HNC-局部联想脉络

    局部联想脉络 概念分为:抽象概念.具体概念 对抽象概念用 五元组 和 语义网络 表达 对具体概念用 挂靠展开近似 表达 五元组:动态.静态.属性.值.效应.(u,g,u,z,r),用于表达抽象概念的外 ...