站長(zhǎng)資訊網(wǎng)
最全最豐富的資訊網(wǎng)站

什么是接口?如何在PHP中使用接口編寫優(yōu)雅的代碼?

什么是接口?如何在PHP中使用接口?本篇文章帶大家聊聊使用接口編寫更優(yōu)雅的 PHP 代碼,希望對(duì)大家有所幫助!

什么是接口?如何在PHP中使用接口編寫優(yōu)雅的代碼?

在編程中,確保代碼可讀、可維護(hù)、可擴(kuò)展和易于測(cè)試是很重要的;而使用接口,恰恰是我們改進(jìn)代碼中所有這些因素的方法之一。

目標(biāo)讀者

本文的目標(biāo)讀者是對(duì) OOP(面向?qū)ο缶幊蹋└拍钣谢玖私獠⒃?PHP 中使用繼承的開(kāi)發(fā)人員。如果你知道如何在 PHP 代碼中使用繼承,那么你應(yīng)該可以很好地理解本文。

什么是接口?

簡(jiǎn)而言之,接口只是對(duì)類應(yīng)該做什么的描述,它們可用于確保實(shí)現(xiàn)該接口的任何類都將包括在其內(nèi)部定義的每個(gè)公共方法。

接口可以

  • 用于定義類的公共方法;
  • 用于定義類的常量。

接口不可以

  • 被實(shí)例化;
  • 用于定義類的私有或受保護(hù)方法;
  • 用于定義類的屬性。

接口是用來(lái)定義一個(gè)類應(yīng)該包括的公共方法的。記住,你只需要在接口里定義方法的簽名,而不需要包含方法的主體(就像通常在類中看到的方法一樣)。**這是因?yàn)榻涌趦H用于定義對(duì)象之間的通信,而不是像在類中那樣定義通信和行為。**為了說(shuō)明這個(gè)問(wèn)題,下面展示了一個(gè)定義了幾個(gè)公共方法的示例接口:

interface DownloadableReport {     public function getName(): string;      public function getHeaders(): array;      public function getData(): array; }

根據(jù) php.net 文檔我們可以知道,接口有兩個(gè)主要用途:

  • 允許開(kāi)發(fā)者創(chuàng)建不同類別的對(duì)象,這些對(duì)象可以互換使用,因?yàn)樗鼈儗?shí)現(xiàn)了相同的一個(gè)或多個(gè)接口。常見(jiàn)的例子包含:多個(gè)數(shù)據(jù)庫(kù)訪問(wèn)服務(wù)、多個(gè)支付網(wǎng)關(guān)、不同的緩存策略等。不同的實(shí)現(xiàn)之間可以互換,而不需要對(duì)使用它們的代碼進(jìn)行任何修改。

  • 允許函數(shù)或方法接受符合接口的參數(shù)并對(duì)其進(jìn)行操作,而不關(guān)心該對(duì)象還可以做什么或它是如何實(shí)現(xiàn)的。這些接口通常被命名為 IterableCacheableRenderable 等,來(lái)說(shuō)明這些接口的實(shí)際含義。

在 PHP 中使用接口

接口是 OOP(面向?qū)ο缶幊蹋┐a庫(kù)的重要部分。接口能讓我們降低代碼耦合并提高可擴(kuò)展性。舉個(gè)例子,讓我們看看下面這個(gè)類:

class BlogReport {     public function getName(): string     {         return 'Blog report';     } }

如你所見(jiàn),我們定義了一個(gè)類,類中有一個(gè)函數(shù),返回一個(gè)字符串。這樣一來(lái),我們定義了該方法的行為,所以我們知道 getName() 是如何返回字符串的。不過(guò),假設(shè)我們?cè)诹硪粋€(gè)類調(diào)用這個(gè)方法;這個(gè)類不需要關(guān)心這個(gè)字符串如何構(gòu)建的,它只關(guān)心該方法是否返回內(nèi)容。舉例來(lái)說(shuō),讓我們看看如何在另一個(gè)類調(diào)用此方法:

class ReportDownloadService {     public function downloadPDF(BlogReport $report)     {         $name = $report->getName();          // 下載文件……     } }

盡管上面的代碼正常運(yùn)行,但我們?cè)O(shè)想一下,現(xiàn)在想給 UsersReport 類中增加下載用戶報(bào)告的功能。顯然,我們不能使用 ReportDownloadService 中的現(xiàn)有方法,因?yàn)槲覀円呀?jīng)強(qiáng)制規(guī)定方法只能傳遞 BlogReport 類。因此,我們必須修改把原有的下載方法名稱改掉(避免重名),然后另外再添加一個(gè)類似的方法,如下所示:

class ReportDownloadService {     public function downloadBlogReportPDF(BlogReport $report)     {         $name = $report->getName();          // 下載文件……     }      public function downloadUsersReportPDF(UsersReport $report)     {         $name = $report->getName();          // 下載文件……     } }

假設(shè)上面的方法中的下載文件部分(注釋掉的部分)使用了相同的代碼,而且我們可以將這些相同的代碼單獨(dú)寫成一個(gè)方法,但我們?nèi)詴?huì)有一些重復(fù)的代碼(譯者注:指的是每個(gè)方法中都會(huì)有 $name = $report->getName();)以及有多個(gè)幾乎相同的類的入口。這可能會(huì)給將來(lái)擴(kuò)展代碼或測(cè)試帶來(lái)額外的工作量。

例如,假設(shè)我們創(chuàng)建了一個(gè)新的 AnalyticsReport;我們現(xiàn)在需要向該類添加一個(gè)新的 downloadAnalyticsReportPDF() 方法。你可以清晰的看到這個(gè)文件將如何膨脹(譯者注:指每增加一個(gè)類型,就要增加一個(gè)下載方法)。這就是一個(gè)使用接口的完美場(chǎng)景!

讓我們從創(chuàng)建第一個(gè)接口開(kāi)始:讓我們將其命名為 DownloadableReport,定義如下:

interface DownloadableReport {     public function getName(): string;      public function getHeaders(): array;      public function getData(): array; }

我們現(xiàn)在可以更新 BlogReportUsersReport 來(lái)實(shí)現(xiàn) DownloadableReport 接口,如下例所示。但是請(qǐng)注意,作為演示用途,我故意把 UsersReport 中的代碼寫錯(cuò)了:

class BlogReport implements DownloadableReport {     public function getName(): string     {         return 'Blog report';     }      public function getHeaders(): array     {         return ['The headers go here'];     }      public function getData(): array     {         return ['The data for the report is here.'];     } }
class UsersReport implements DownloadableReport {     public function getName()     {         return ['Users Report'];     }      public function getData(): string     {         return 'The data for the report is here.';     } }

但當(dāng)我們嘗試運(yùn)行代碼的時(shí)候,我們將會(huì)收到錯(cuò)誤,原因如下:

  • 缺少 getHeaders() 方法.

  • getName() 方法不包括接口的方法簽名中定義的返回類型。

  • getData() 方法定義了一個(gè)返回類型,但它與接口的方法簽名中定義的類型不同。

因此,為了修復(fù) UsersReport 使其正確實(shí)現(xiàn) DownloadableReport 接口,我們可以將其修改為:

class UsersReport implements DownloadableReport {     public function getName(): string     {         return 'Users Report';     }      public function getHeaders(): array     {        return [];     }      public function getData(): array     {         return ['The data for the report is here.'];     } }

現(xiàn)在兩個(gè)報(bào)告類都實(shí)現(xiàn)了相同的接口,我們可以這樣更新我們的 ReportDownloadService

class ReportDownloadService {     public function downloadReportPDF(DownloadableReport $report)     {         $name = $report->getName();          // 下載文件……     }  }

我們現(xiàn)在可以把 UsersReportBlogReport 對(duì)象傳入 downloadReportPDF 方法中,而且不會(huì)出現(xiàn)任何錯(cuò)誤。這是因?yàn)槲覀冎涝搶?duì)象實(shí)現(xiàn)了報(bào)告類的必要方法,并且將返回我們期望的數(shù)據(jù)類型。

通過(guò)向方法傳遞了一個(gè)接口,而不是一個(gè)具體的類,我們可以根據(jù)方法的實(shí)際作用(而不是方法的實(shí)現(xiàn)原理)來(lái)解耦 ReportDownloadService類和這些報(bào)告類。

如果我們想創(chuàng)建一個(gè)新的 AnalyticsReport,我們可以讓它實(shí)現(xiàn)相同的接口。這樣一來(lái),我們不必添加任何新的方法,只需要將報(bào)告對(duì)象傳遞給同一個(gè)的 downloadReportPDF() 方法。如果你正在構(gòu)建你自己的包或框架,接口可能對(duì)你特別有用。你只需要告訴使用者要實(shí)現(xiàn)哪個(gè)接口,然后他們就可以創(chuàng)建自己的類。例如,在 Laravel 中,我們可以通過(guò)實(shí)現(xiàn) IlluminateContractsCacheStore 接口來(lái)創(chuàng)建自己的自定義緩存驅(qū)動(dòng)類。

除了能改進(jìn)代碼之外,我喜歡使用接口的另一個(gè)原因是 —— 它們起到了“代碼即文檔”的作用。例如,如果我想弄清楚一個(gè)類能做什么,不能做什么,我傾向于先看接口,然后再看實(shí)現(xiàn)它的類。接口能夠告訴我們所有可被調(diào)用的方法,而不需要我們過(guò)多地關(guān)心這些方法的底層實(shí)現(xiàn)方式是怎樣的。

值得注意的是,Laravel 中的“契約(contract)”和“接口(interface)”這兩個(gè)詞語(yǔ)是可互換的。根據(jù) Laravel 文檔,“契約是一組由框架提供的核心服務(wù)的接口”。所以,記住:契約是一個(gè)接口,但接口不一定是契約。通常情況下,契約只是框架提供的一個(gè)接口。關(guān)于使用契約的

贊(0)
分享到: 更多 (0)
網(wǎng)站地圖   滬ICP備18035694號(hào)-2    滬公網(wǎng)安備31011702889846號(hào)
亚洲精品乱码久久久久蜜桃| 加勒比精品久久一区二区三区| 亚洲欧美日韩中文二区| 精品无人码麻豆乱码1区2区| 精品国产福利久久久| 国产精品免费大片一区二区| 精品天海翼一区二区| 精品人妻无码一区二区色欲产成人 | 中文字幕日韩精品在线| 日韩高清在线不卡| 国产尤物在线视精品在亚洲| 亚洲色精品三区二区一区| 久久久免费精品re6| 亚洲精品乱码久久久久久中文字幕| 日韩在线精品一二三区| 国产农村妇女精品一二区| 国产精品久久无码一区二区三区网| 777精品成人影院| 午夜精品久久久久久久| 国产在线精品福利大全| 国产VA免费精品高清在线| 五月花精品视频在线观看 | 国产精品极品美女自在线观看| 最新欧美精品一区二区三区| 日韩福利在线视频| 日韩av无码久久精品免费| 国产精品国产三级国产av剧情| 精品久久人妻av中文字幕| 精品视频无码一区二区三区| 久久国内精品自在自线软件| 国产精品久久久久jk制服| 校园春色国产精品| 国产精品国产AV片国产| 亚洲欧美日韩国产精品一区| 国产精品一二三区| 91麻豆精品国产91久久久久久| 久久夜色精品国产噜噜噜亚洲AV| 国产精品免费无遮挡无码永久视频| 国产精品第一页在线| 国产精品视频久久久| 97精品在线观看|