[toc]
一、abstract
1肛走、抽象類
在實際開發(fā)中辙芍,我們可以有這樣一種類,是其它類的父類羹与,但是他本身并不需要去實例化故硅,主要用途是用于讓子類來繼承,這樣可以達(dá)到代碼的復(fù)用纵搁,同時利于項目設(shè)計者去設(shè)計類吃衅。
- 定義抽象類:
abstract class 類名{
//屬性
//方法
}
- 繼承抽象類
class 類名 extends 抽象類
{
}
2、抽象方法
抽象方法不能有方法體腾誉。所謂沒有方法體就是在方法聲明的時候沒有大括號以及其中的內(nèi)容徘层,而是直接聲明時在方法名后加上分號結(jié)束。
- 如:
abstract function 方法名();
3利职、注意
1)如果一個類使用了abstract來修飾趣效,則該類就是抽象類(不能被實例化)。
2)抽象類可以沒有抽象方法猪贪,同時還可以有實現(xiàn)了的方法跷敬。
3)一個類只要有abstract方法,則該類必須聲明為abstract類热押。
4)抽象方法是作為子類方法重載的模板使用的西傀,如果一個A類繼承了一個抽象B類,則要求A類實現(xiàn)B類的所有抽象方法(除非A類也是抽象類)桶癣。
5)如果子類沒有全部實現(xiàn)抽象類中的所有抽象方法拥褂,那么該子類也是一個抽象類,必須在 class 前面加上 abstract 關(guān)鍵字牙寞,并且不能被實例化饺鹃。
6)抽象方法不能為private。
二、interface
1悔详、簡介
接口就是給出一些沒有實現(xiàn)的方法镊屎,封裝到一起,到某個類要使用的時候伟端,再根據(jù)具體情況把這些方法寫出來杯道。
接口是更加抽象的抽象類匪煌,抽象類可以存在有方法體的方法责蝠,而接口里的所有方法都沒有方法體。
接口體現(xiàn)了程序設(shè)計的多態(tài)和高內(nèi)聚低偶合的設(shè)計思想萎庭。
2霜医、定義接口類
interface A
{
public function a();
Public function b();
}
3、實現(xiàn)接口類
class X implements A
{
public function a(){
}
public function a(){
}
}
4驳规、注意
1)不能去實例化一個接口肴敛。
2)接口中的所有方法都不能有方法體。
3)一個接口可以繼承多個其它接口吗购。
4)一個類可以實現(xiàn)多個接口(用逗號隔開)医男。
5)接口中可以有屬性,但必須是常量捻勉,默認(rèn)是public镀梭。
6)接口的方法必須都是public,默認(rèn)public踱启。(但將常量變量放在接口中違背了其作為接口的作用而存在的宗旨报账,也混淆了interface與類的不同價值。所以不建議)
7)一個類可以同時繼承又實現(xiàn)某些接口埠偿。(extends子句應(yīng)該在implements子句之前)
8)任何實現(xiàn)接口的類都要實現(xiàn)接口中所定義的所有方法透罢。
三、Abstract Class與Interface的異同
1冠蒋、 相同點:
1)兩者都是抽象類羽圃,都不能實例化。
2)interface 實現(xiàn)類及 abstract class 的子類都必須要實現(xiàn)已經(jīng)聲明的抽象方法抖剿。
2统屈、不同點:
1)interface需要實現(xiàn),要用 implements 牙躺;而 abstract class 需要繼承愁憔,要用 extends 。
2)一個類可以實現(xiàn)多個 interface 孽拷,但一個類只能繼承一個abstract class吨掌。
3) interface 中的每一個方法都是抽象方法,實現(xiàn)類必須要實現(xiàn);而 abstract class 的子類可以有選擇地實現(xiàn)膜宋。
4)接口中的抽象方法前不用也不能加 abstract 關(guān)鍵字窿侈,默認(rèn)隱式就是抽象方法,也不能加 final 關(guān)鍵字來防止抽象方法的繼承秋茫;而抽象類中抽象方法前則必須加上 abstract 表示顯示聲明為抽象方法史简。
5)接口中的抽象方法默認(rèn)是 public 的,也只能是 public 的肛著;而抽象類中的抽象方法則可以用 public 或 protected 來修飾圆兵,但不能用 private 。
四枢贿、Interface經(jīng)典實例
需求:
我需要從不同的源收集文本殉农。(可以從遠(yuǎn)程URL讀取HTML,可以讀取流資源局荚,也可以收集終端命令的輸出)
1超凳、定義Documentable接口
實現(xiàn)Documentable接口的任何類都必須實現(xiàn)接口的getId()方法與getContent()方法。
<?php
interface Documentable
{
public function getId();
public function getContent();
}
2耀态、定義三種實現(xiàn)方式
定義以上接口的用處是轮傍,我們可以分開定義獲取文檔的類,而且能使用十分不同的實現(xiàn)方式首装。
1)定義HtmlDocument類
<?php
class HtmlDocument implements Documentable
{
protected $url;
public function __construct($url)
{
$this->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類
<?php
class StreamDocument implements Documentable
{
protected $resource;
protected $buffer;
public function __construct($resource, $buffer = 4096)
{
$this->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類
<?php
class CommandOutputDocument implements Documentable
{
protected $command;
public function __construct($command)
{
$this->command = $command;
}
public function getId()
{
return $this->command;
}
public function getContent()
{
return shell_exec($this->command);
}
}
3创夜、定義DocumentStore類
<?php
class DocumentStore
{
protected $data = [];
public function addDocument(Documentable $document)
{
$key = $document->getId();
$value = $document->getContent();
$this->data[$key] = $value;
}
public function getDocuments()
{
return $this->data;
}
}
4、使用DocumentStore類
<?php
require 'Documentable.php';
require 'DocumentStore.php';
require 'HtmlDocument.php';
require 'StreamDocument.php';
require 'CommandOutputDocument.php';
$documentStore = new DocumentStore();
// Add HTML document
$htmlDoc = new HtmlDocument('http://php.net');
$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());
總結(jié):
使用接口編寫的代碼更靈活簿盅,能委托別人實現(xiàn)細(xì)節(jié)挥下。使用接口后會有起來越多的人使用你的代碼,因為他們只需要知道如何實現(xiàn)接口桨醋,就可以無縫地使用你的代碼棚瘟。
源碼地址:https://github.com/codeguy/modern-php/tree/master/02-features/interfaces
五、參考
《Modern PHP》Josh Lockhart 著 安道 譯