PHP强化之18|PHP强化之18 - 抽象类与接口

[toc]
一、abstract 1、抽象类
在实际开发中,我们可以有这样一种类,是其它类的父类,但是他本身并不需要去实例化,主要用途是用于让子类来继承,这样可以达到代码的复用,同时利于项目设计者去设计类。

  • 定义抽象类:
abstract class 类名{ //属性 //方法 }

  • 继承抽象类
class 类名 extends 抽象类 { }

2、抽象方法
抽象方法不能有方法体。所谓没有方法体就是在方法声明的时候没有大括号以及其中的内容,而是直接声明时在方法名后加上分号结束。
  • 如:
abstract function 方法名();

3、注意
1)如果一个类使用了abstract来修饰,则该类就是抽象类(不能被实例化)。
2)抽象类可以没有抽象方法,同时还可以有实现了的方法。
3)一个类只要有abstract方法,则该类必须声明为abstract类。
4)抽象方法是作为子类方法重载的模板使用的,如果一个A类继承了一个抽象B类,则要求A类实现B类的所有抽象方法(除非A类也是抽象类)。
5)如果子类没有全部实现抽象类中的所有抽象方法,那么该子类也是一个抽象类,必须在 class 前面加上 abstract 关键字,并且不能被实例化。
6)抽象方法不能为private。
二、interface 1、简介
接口就是给出一些没有实现的方法,封装到一起,到某个类要使用的时候,再根据具体情况把这些方法写出来。
接口是更加抽象的抽象类,抽象类可以存在有方法体的方法,而接口里的所有方法都没有方法体。
接口体现了程序设计的多态和高内聚低偶合的设计思想。
2、定义接口类
interface A { public function a(); Public function b(); }

3、实现接口类
class X implements A { public function a(){ } public function a(){ } }

4、注意
1)不能去实例化一个接口。
2)接口中的所有方法都不能有方法体。
3)一个接口可以继承多个其它接口。
4)一个类可以实现多个接口(用逗号隔开)。
5)接口中可以有属性,但必须是常量,默认是public。
6)接口的方法必须都是public,默认public。(但将常量变量放在接口中违背了其作为接口的作用而存在的宗旨,也混淆了interface与类的不同价值。所以不建议)
7)一个类可以同时继承又实现某些接口。(extends子句应该在implements子句之前)
8)任何实现接口的类都要实现接口中所定义的所有方法。
三、Abstract Class与Interface的异同 1、 相同点:
1)两者都是抽象类,都不能实例化。
2)interface 实现类及 abstract class 的子类都必须要实现已经声明的抽象方法。
2、不同点:
1)interface需要实现,要用 implements ;而 abstract class 需要继承,要用 extends 。
2)一个类可以实现多个 interface ,但一个类只能继承一个abstract class。
3) interface 中的每一个方法都是抽象方法,实现类必须要实现;而 abstract class 的子类可以有选择地实现。
4)接口中的抽象方法前不用也不能加 abstract 关键字,默认隐式就是抽象方法,也不能加 final 关键字来防止抽象方法的继承;而抽象类中抽象方法前则必须加上 abstract 表示显示声明为抽象方法。
5)接口中的抽象方法默认是 public 的,也只能是 public 的;而抽象类中的抽象方法则可以用 public 或 protected 来修饰,但不能用 private 。
四、Interface经典实例 需求:
我需要从不同的源收集文本。(可以从远程URL读取HTML,可以读取流资源,也可以收集终端命令的输出)
1、定义Documentable接口
实现Documentable接口的任何类都必须实现接口的getId()方法与getContent()方法。

2、定义三种实现方式
定义以上接口的用处是,我们可以分开定义获取文档的类,而且能使用十分不同的实现方式。
1)定义HtmlDocument类
url = $url; } public function getId() { return $this->url; } public function getContent() { $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $this->url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 3); curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1); curl_setopt($ch, CURLOPT_MAXREDIRS, 3); $html = curl_exec($ch); curl_close($ch); return $html; } }

2)定义StreamDocument类
resource = $resource; $this->buffer = $buffer; } public function getId() { return 'resource-' . (int)$this->resource; } public function getContent() { $streamContent = ''; rewind($this->resource); while (feof($this->resource) === false) { $streamContent .= fread($this->resource, $this->buffer); } return $streamContent; } }

3)定义CommandOutputDocument类
command = $command; } public function getId() { return $this->command; } public function getContent() { return shell_exec($this->command); } }

3、定义DocumentStore类
getId(); $value = https://www.it610.com/article/$document->getContent(); $this->data[$key] = $value; } public function getDocuments() { return $this->data; } }

4、使用DocumentStore类
addDocument($htmlDoc); // Add stream document $streamDoc = new StreamDocument(fopen('stream.txt', 'rb')); $documentStore->addDocument($streamDoc); // Add terminal command document $cmdDoc = new CommandOutputDocument('cat /etc/hosts'); $documentStore->addDocument($cmdDoc); print_r($documentStore->getDocuments());

总结:
使用接口编写的代码更灵活,能委托别人实现细节。使用接口后会有起来越多的人使用你的代码,因为他们只需要知道如何实现接口,就可以无缝地使用你的代码。
源码地址:https://github.com/codeguy/modern-php/tree/master/02-features/interfaces
五、参考 【PHP强化之18|PHP强化之18 - 抽象类与接口】《Modern PHP》Josh Lockhart 著 安道 译

    推荐阅读