中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

如何用接口寫高質量PHP代碼

發布時間:2021-11-08 16:05:06 來源:億速云 閱讀:98 作者:iii 欄目:編程語言

本篇內容介紹了“如何用接口寫高質量PHP代碼”的有關知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領大家學習一下如何處理這些情況吧!希望大家仔細閱讀,能夠學有所成!                            

概述

在編碼中,有一個重要的事情是確保你的代碼是可讀的、可維護的、可擴展的、易于測試的。我們可以改善這些問題的方法之一就是使用接口(interface)。

目標受眾

本文針對對 OOP(object oriented programming)概念和 PHP 中的繼承有基本理解的開發者,如果你知道如何在 PHP 中使用繼承,那么這篇文章會更容易理解一些。

什么是接口?

基本上,接口描述了一個類「該做什么」。接口被用于確保實現接口的任何類中都包含接口規定的公共方法。

接口可以

  • 用于定義類中的公共方法。

  • 用于定義類中的常量。

接口不可以

  • 單獨實例化。

  • 用于定義類中的私有(private)或保護(protected)方法。

  • 用于定義類中的屬性。

接口口用于定義一個類中應該包括的公共方法。需要記住的是,接口只定義了方法名和參數以及返回值,但不包含方法體。這是因為接口僅用于定義對象間的通信,而不是定義類之間通信的具體行為。為了給出一點上下文,這個實例展示了一個定義了幾個公共方法的示例接口:

interface DownloadableReport
{
    public function getName(): string;

    public function getHeaders(): array;

    public function getData(): array;
}

根據 php.net 介紹,接口有兩個主要用途:

  1. 允許開發人員創建不同類的對象,這些對象可以互換使用,因為它們實現相同的接口。一個常見的例子是多個數據庫訪問服務,多個支付網關或不同的緩存策略。可以更換不同的實現,而無需對使用它們的代碼進行任何更改。

  2. 允許函數或方法接受符合接口的參數并對其進行操作,而不關心對象還可以做什么或它是如何實現的。這些接口通常被命名為 Iterable,Cacheable,Renderable 等等來描述行為的含義。【推薦學習:《PHP視頻教程》】

在 PHP 中使用接口

接口是 OOP (面向對象編程) 代碼中非常重要的一部分。它們允許我們將代碼解耦并提高可擴展性。舉一個例子,讓我們看看下面這個類:

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

如您所見,我們已經定義了一個帶有返回字符串的方法的類。通過這樣做,我們已經確定了方法的行為,因此我們可以看到getName()是如何構建返回的字符串的。但是,假設我們在另一個類中的代碼中調用此方法。另一個類并不會關心字符串是如何構建的,它只關心它是否被返回。例如,讓我們看看如何在另一個類中調用此方法:

class ReportDownloadService
{
    public function downloadPDF(BlogReport $report)
    {
        $name = $report->getName();

        // 在這里下載文件...
    }
}

盡管上面的代碼已經可以用了,讓我們設想一下,若是我們現在想要在 UserReport 類中增加一個下載用戶報告的方法。當然,我們不能使用 ReportDownloadService 中已經存在的方法,因為我們已經強制只能傳入一個 BlogReport 類。因此,我們必須重命名現有方法,再添加一個新的方法。像這樣:

class ReportDownloadService
{
    public function downloadBlogReportPDF(BlogReport $report)
    {
        $name = $report->getName();

        // 在這下載文件...
    }

    public function downloadUsersReportPDF(UsersReport $report)
    {
        $name = $report->getName();

        // 在這下載文件...
    }
}

雖然你實際看不到,但我們假設上述的類中,其余的方法都使用相同的代碼來構建下載。我們可以將公共的代碼提升為方法,但我們仍然會有一些公共的代碼。除此之外,我們還有多個進入這個類的幾乎是相同代碼的入口。這可能會在未來嘗試擴展代碼或添加測試功能時導致額外的工作量。

舉個例子,我們創建一個新的 AnalyticsReport;我們現在需要為這個類增加一個新的 downloadAnalyticsReportPDF() 方法。這時你可能會觀察到這個文件正在快速增長。這時就是使用接口的絕佳時機。

我們從創建一個接口開始。我們要創建一個叫做 DownloadableReport 的接口,并這樣定義:

interface DownloadableReport
{
    public function getName(): string;

    public function getHeaders(): array;

    public function getData(): array;
}

我們現在要更改 BlogReportUsersReport 來實現 DownloadableReport 接口,如下所示。我故意寫錯了 UsersReport 的代碼來演示一些東西。

class BlogReport implements DownloadableReport
{
    public function getName(): string
    {
        return '博客報告';
    }

    public function getHeaders(): array
    {
        return ['頭在這'];
    }

    public function getData(): array
    {
        return ['報告的數據在這里'];
    }
}
class UsersReport implements DownloadableReport
{
    public function getName()
    {
        return ['用戶報告'];
    }

    public function getData(): string
    {
        return '報告的數據在這里';
    }
}

如果我們嘗試運行這段代碼,我們會得到報錯,原因是:

  1. 找不到 getHeaders() 方法。

  2. getName() 方法返回類型在接口中定義的方法返回值類型中。

  3. getData() 方法定義了返回類型,但和接口中定義的返回類型不同。

因此,要讓 UsersReport 正確地實現 DownloadableReport 接口,我們需要作如下變動:

class UsersReport implements DownloadableReport
{
    public function getName(): string
    {
        return '用戶報告';
    }

    public function getHeaders(): array
    {
       return [];
    }

    public function getData(): array
    {
        return ['報告的數據在這里'];
    }
}

現在我們兩個報告類都實現了相同的接口,我們可以像這樣更新我們的 ReportDownloadService

class ReportDownloadService
{
    public function downloadReportPDF(DownloadableReport $report)
    {
        $name = $report->getName();

        // 在這下載文件
    }

}

現在我們向 downloadReportPDF() 方法傳入了 UsersReportBlogReport 對象,沒有任何錯誤出現。這是因為我們現在知道了報告類所需要的必要方法,并且報告類會按照我們預期的類型返回數據。

向方法傳入接口,而不是向類傳入接口,這樣的結果使得 ReportDownloadService 和報告類產生松散耦合,這根據的是方法做什么,而不是如何做

如果我們想要創建一個新的 AnalyticsReport,我們需要讓它實現相同的接口,然后它就會允許我們將報告類實例傳入相同的 downloadReportPDF() 方法中,而不用添加其他新的方法。如果你正在構建自己的應用或框架,想要讓其他開發人員有創建給他們自己的類的功能,這將非常有用。舉個例子,在 Laravel 中,你可以通過實現 Illuminate\Contracts\Cache\Store 接口來創建自定義的緩存類。

除了使用接口來改進代碼外,我更傾向于喜歡接口的「代碼即文檔」特性。舉個例子,如果我想要知道一個類能做什么和不能做什么,我更喜歡在查看類之前先查看接口。它會告訴我所有可調用的方法,而不需要關心這些方法具體是怎么運行的。

對于像我這樣的 Laravel 開發者來說,值得注意的一件事是,你會經常看到 接口 interface契約 contract 交替使用。根據 Laravel 文檔,「Laravel 的契約是一組定義了框架提供的核心服務的接口」。因此,契約是一個接口,但接口不一定是契約。通常來說,契約只是框架提供的一個接口。有關契約的更多內容,我建議閱讀一下 文檔,因為我認為它在契約的理解和使用途徑上有很好的見解。

“如何用接口寫高質量PHP代碼”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識可以關注億速云網站,小編將為大家輸出更多高質量的實用文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

php
AI

奇台县| 白玉县| 甘泉县| 公主岭市| 汝南县| 开江县| 察隅县| 双流县| 宜黄县| 普陀区| 尼木县| 阿巴嘎旗| 桂平市| 玛纳斯县| 涟水县| 洪江市| 长子县| 南京市| 右玉县| 侯马市| 河西区| 定兴县| 桐庐县| 安图县| 南京市| 凤山市| 安多县| 巢湖市| 彩票| 长顺县| 湖南省| 浮山县| 塘沽区| 胶南市| 澜沧| 荥阳市| 礼泉县| 西乡县| 左云县| 德州市| 通江县|