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