PHP中抽象类与接口的区别

1.抽象类与接口的区别

在学习PHP面向对象时,都会在抽象类与接口上迷惑,作用差不多为什么还那么容易混淆,何不留一去一?但是事实上两者的区别还是很大的,如果能够很好地运用PHP的两个方法,面向对象的程序设计将会更加合理、清晰高效。

a.接口是通过 interface 关键字来定义的, 抽象类是通过abstract关键字来定义的。

b.对接口的使用方式是通过关键字implements来实现的,而对于抽象类的操作是使用类继承的关键字extends实现的,使用时要特别注意。

c.接口没有数据成员,但是抽象类有数据成员,抽象类可以实现数据的封装。

d.接口没有构造函数,抽象类可以有构造函数。

e.接口中的方法都是public类型,而抽象类中的方法可以使用private、protected或public来修饰。

f.一个类可以同时实现多个接口,但是只能实现一个抽象类。

相同点:抽象方法与接口的函数体内不能写任何东西,连两个大括号都不能写!!!如:function getName();这样就行了

2.接口

使用接口(interface),可以指定某个类必须实现哪些方法,但不需要定义这些方法的具体内容。

接口是通过 interface 关键字来定义的,就像定义一个标准的类一样,但其中定义所有的方法都是空的。

接口中定义的所有方法都必须是公有,这是接口的特性。

实现(implements)

要实现一个接口,使用 implements 操作符。类中必须实现接口中定义的所有方法,否则会报一个致命错误。类可以实现多个接口,用逗号来分隔多个接口的名称。

Note:

实现多个接口时,接口中的方法不能有重名。

Note:

接口也可以继承,通过使用 extends 操作符。

Note:

类要实现接口,必须使用和接口中所定义的方法完全一致的方式。否则会导致致命错误。

常量

接口中也可以定义常量。接口常量和类常量的使用完全相同,但是不能被子类或子接口所覆盖。

  1 <?php
  2 
  3 // 声明一个'iTemplate'接口
  4 interface iTemplate
  5 {
  6     public function setVariable($name, $var);
  7     public function getHtml($template);
  8 }
  9 
 10 
 11 // 实现接口
 12 // 下面的写法是正确的
 13 class Template implements iTemplate
 14 {
 15     private $vars = array();
 16   
 17     public function setVariable($name, $var)
 18     {
 19         $this->vars[$name] = $var;
 20     }
 21   
 22     public function getHtml($template)
 23     {
 24         foreach($this->vars as $name => $value) {
 25             $template = str_replace('{' . $name . '}', $value, $template);
 26         }
 27  
 28         return $template;
 29     }
 30 }
 31 
 32 // 下面的写法是错误的,会报错,因为没有实现 getHtml():
 33 // Fatal error: Class BadTemplate contains 1 abstract methods
 34 // and must therefore be declared abstract (iTemplate::getHtml)
 35 class BadTemplate implements iTemplate
 36 {
 37     private $vars = array();
 38   
 39     public function setVariable($name, $var)
 40     {
 41         $this->vars[$name] = $var;
 42     }
 43 }
 44 ?>
 45 Example #2 可扩充的接口
 46 
 47 <?php
 48 interface a
 49 {
 50     public function foo();
 51 }
 52 
 53 interface b extends a
 54 {
 55     public function baz(Baz $baz);
 56 }
 57 
 58 // 正确写法
 59 class c implements b
 60 {
 61     public function foo()
 62     {
 63     }
 64 
 65     public function baz(Baz $baz)
 66     {
 67     }
 68 }
 69 
 70 // 错误写法会导致一个致命错误
 71 class d implements b
 72 {
 73     public function foo()
 74     {
 75     }
 76 
 77     public function baz(Foo $foo)
 78     {
 79     }
 80 }
 81 ?>
 82 Example #3 继承多个接口
 83 
 84 <?php
 85 interface a
 86 {
 87     public function foo();
 88 }
 89 
 90 interface b
 91 {
 92     public function bar();
 93 }
 94 
 95 interface c extends a, b
 96 {
 97     public function baz();
 98 }
 99 
100 class d implements c
101 {
102     public function foo()
103     {
104     }
105 
106     public function bar()
107     {
108     }
109 
110     public function baz()
111     {
112     }
113 }
114 ?>
115 Example #4 使用接口常量
116 
117 <?php
118 interface a
119 {
120     const b = 'Interface constant';
121 }
122 
123 // 输出接口常量
124 echo a::b;
125 
126 // 错误写法,因为常量不能被覆盖。接口常量的概念和类常量是一样的。
127 class b implements a
128 {
129     const b = 'Class constant';
130 }
131 ?>

http://php.net/manual/zh/language.oop5.interfaces.php

3.抽象类

PHP 5 支持抽象类和抽象方法。定义为抽象的类不能被实例化。任何一个类,如果它里面至少有一个方法是被声明为抽象的,那么这个类就必须被声明为抽象的。被定义为抽象的方法只是声明了其调用方式(参数),不能定义其具体的功能实现。

继承一个抽象类的时候,子类必须定义父类中的所有抽象方法;另外,这些方法的访问控制必须和父类中一样(或者更为宽松)。例如某个抽象方法被声明为受保护的,那么子类中实现的方法就应该声明为受保护的或者公有的,而不能定义为私有的。此外方法的调用方式必须匹配,即类型和所需参数数量必须一致。例如,子类定义了一个可选参数,而父类抽象方法的声明里没有,则两者的声明并无冲突。 这也适用于 PHP 5.4 起的构造函数。在 PHP 5.4 之前的构造函数声明可以不一样的。

 1 <?php
 2 abstract class AbstractClass
 3 {
 4  // 强制要求子类定义这些方法
 5     abstract protected function getValue();
 6     abstract protected function prefixValue($prefix);
 7 
 8     // 普通方法(非抽象方法)
 9     public function printOut() {
10         print $this->getValue() . "\n";
11     }
12 }
13 
14 class ConcreteClass1 extends AbstractClass
15 {
16     protected function getValue() {
17         return "ConcreteClass1";
18     }
19 
20     public function prefixValue($prefix) {
21         return "{$prefix}ConcreteClass1";
22     }
23 }
24 
25 class ConcreteClass2 extends AbstractClass
26 {
27     public function getValue() {
28         return "ConcreteClass2";
29     }
30 
31     public function prefixValue($prefix) {
32         return "{$prefix}ConcreteClass2";
33     }
34 }
35 
36 $class1 = new ConcreteClass1;
37 $class1->printOut();
38 echo $class1->prefixValue('FOO_') ."\n";
39 
40 $class2 = new ConcreteClass2;
41 $class2->printOut();
42 echo $class2->prefixValue('FOO_') ."\n";
43 ?>
44 以上例程会输出:
45 
46 ConcreteClass1
47 FOO_ConcreteClass1
48 ConcreteClass2
49 FOO_ConcreteClass2
50 Example #2 抽象类示例
51 
52 <?php
53 abstract class AbstractClass
54 {
55     // 我们的抽象方法仅需要定义需要的参数
56     abstract protected function prefixName($name);
57 
58 }
59 
60 class ConcreteClass extends AbstractClass
61 {
62 
63     // 我们的子类可以定义父类签名中不存在的可选参数
64     public function prefixName($name, $separator = ".") {
65         if ($name == "Pacman") {
66             $prefix = "Mr";
67         } elseif ($name == "Pacwoman") {
68             $prefix = "Mrs";
69         } else {
70             $prefix = "";
71         }
72         return "{$prefix}{$separator} {$name}";
73     }
74 }
75 
76 $class = new ConcreteClass;
77 echo $class->prefixName("Pacman"), "\n";
78 echo $class->prefixName("Pacwoman"), "\n";
79 ?>
80 以上例程会输出:
81 
82 Mr. Pacman
83 Mrs. Pacwoman
84 老代码中如果没有自定义类或函数被命名为“abstract”,则应该能不加修改地正常运行。

http://php.net/manual/zh/language.oop5.abstract.php

延伸阅读:

http://www.baidu.com/s?wd=php%20接口%20抽象类%20区别

http://www.sogou.com/web?query=php%20接口%20抽象类%20区别

https://www.so.com/s?q=php%20接口%20抽象类%20区别

http://www.baidu.com/s?wd=php%20抽象类%20实例化

抽象类:http://php.net/manual/zh/language.oop5.abstract.php

接口:http://php.net/manual/zh/language.oop5.interfaces.php

PHP高级——抽象类与接口的区别: http://www.cnblogs.com/picaso/archive/2012/10/05/2711865.html

php抽象类和接口: http://www.cnblogs.com/hylaz/archive/2012/11/11/2765397.html