>  기사  >  백엔드 개발  >  인터페이스란 무엇입니까? PHP의 인터페이스를 사용하여 우아한 코드를 작성하는 방법은 무엇입니까?

인터페이스란 무엇입니까? PHP의 인터페이스를 사용하여 우아한 코드를 작성하는 방법은 무엇입니까?

青灯夜游
青灯夜游앞으로
2022-07-25 20:17:183214검색

인터페이스란 무엇인가요? PHP에서 인터페이스를 사용하는 방법은 무엇입니까? 이 기사에서는 인터페이스를 사용하여 보다 우아한 PHP 코드를 작성하는 방법에 대해 설명합니다. 이것이 여러분에게 도움이 되기를 바랍니다.

인터페이스란 무엇입니까? PHP의 인터페이스를 사용하여 우아한 코드를 작성하는 방법은 무엇입니까?

프로그래밍에서는 코드가 읽기 쉽고, 유지 관리 가능하고, 확장 가능하고, 테스트하기 쉬운지 확인하는 것이 중요하며, 인터페이스를 사용하는 것은 코드의 이러한 모든 요소를 ​​개선할 수 있는 방법 중 하나입니다.

대상 독자

이 기사의 대상 독자는 OOP(객체 지향 프로그래밍) 개념에 대한 기본적인 이해가 있고 PHP에서 상속을 사용하는 개발자입니다. PHP 코드에서 상속을 사용하는 방법을 알고 있다면 이 기사를 잘 이해하고 있어야 합니다.

인터페이스란 무엇인가요?

간단히 말해서 인터페이스는 클래스가 수행해야 하는 작업에 대한 간단한 설명이며, 인터페이스를 구현하는 모든 클래스에 정의된 모든 공용 메서드가 포함되도록 하는 데 사용할 수 있습니다.

Interface:

  • 클래스의 공개 메서드를 정의하는 데 사용되며
  • 클래스의 상수를 정의하는 데 사용할 수 있습니다.

인터페이스 :

  • 인스턴스화할 수 없습니다.
  • 클래스의 비공개 또는 보호 메서드를 정의하는 데 사용할 수 있습니다.
  • 클래스의 속성을 정의하는 데 사용할 수 있습니다.

인터페이스는 클래스에 포함되어야 하는 공개 메서드를 정의하는 데 사용됩니다. 기억하세요. 인터페이스에서 메서드의 시그니처만 정의하면 되며 메서드 본문을 포함할 필요는 없습니다(일반적으로 클래스에서 메서드를 보는 것처럼). **인터페이스는 클래스처럼 통신 및 동작을 정의하는 것이 아니라 객체 간의 통신을 정의하는 데만 사용되기 때문입니다. **이 문제를 설명하기 위해 다음은 여러 공용 메소드를 정의하는 예제 인터페이스를 보여줍니다.

interface DownloadableReport
{
    public function getName(): string;

    public function getHeaders(): array;

    public function getData(): array;
}

php.net 문서에 따르면 인터페이스에는 두 가지 주요 목적이 있음을 알 수 있습니다.

  • 개발자가 생성하도록 허용 동일한 인터페이스를 구현하기 때문에 상호 교환적으로 사용할 수 있는 다양한 객체 클래스입니다. 일반적인 예로는 여러 데이터베이스 액세스 서비스, 여러 결제 게이트웨이, 다양한 캐싱 전략 등이 있습니다. 이를 사용하는 코드를 수정하지 않고도 다양한 구현을 교환할 수 있습니다.

  • 함수나 메소드가 인터페이스에 맞는 매개변수를 허용하고 객체가 수행할 수 있는 다른 작업이나 구현 방법에 신경 쓰지 않고 해당 매개변수에 대해 작업할 수 있도록 합니다. 이러한 인터페이스는 실제로 무엇을 의미하는지 설명하기 위해 일반적으로 Iterable, Cacheable, Renderable 등으로 명명됩니다. IterableCacheableRenderable 等,来说明这些接口的实际含义。

在 PHP 中使用接口

接口是 OOP(面向对象编程)代码库的重要部分。接口能让我们降低代码耦合并提高可扩展性。举个例子,让我们看看下面这个类:

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

如你所见,我们定义了一个类,类中有一个函数,返回一个字符串。这样一来,我们定义了该方法的行为,所以我们知道 getName() 是如何返回字符串的。不过,假设我们在另一个类调用这个方法;这个类不需要关心这个字符串如何构建的,它只关心该方法是否返回内容。举例来说,让我们看看如何在另一个类调用此方法:

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

        // 下载文件……
    }
}

尽管上面的代码正常运行,但我们设想一下,现在想给 UsersReport 类中增加下载用户报告的功能。显然,我们不能使用 ReportDownloadService 中的现有方法,因为我们已经强制规定方法只能传递 BlogReport 类。因此,我们必须修改把原有的下载方法名称改掉(避免重名),然后另外再添加一个类似的方法,如下所示:

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

        // 下载文件……
    }

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

        // 下载文件……
    }
}

假设上面的方法中的下载文件部分(注释掉的部分)使用了相同的代码,而且我们可以将这些相同的代码单独写成一个方法,但我们仍会有一些重复的代码(译者注:指的是每个方法中都会有 $name = $report->getName();)以及有多个几乎相同的类的入口。这可能会给将来扩展代码或测试带来额外的工作量。

例如,假设我们创建了一个新的 AnalyticsReport;我们现在需要向该类添加一个新的 downloadAnalyticsReportPDF() 方法。你可以清晰的看到这个文件将如何膨胀(译者注:指每增加一个类型,就要增加一个下载方法)。这就是一个使用接口的完美场景!

让我们从创建第一个接口开始:让我们将其命名为 DownloadableReport,定义如下:

interface DownloadableReport
{
    public function getName(): string;

    public function getHeaders(): array;

    public function getData(): array;
}

我们现在可以更新 BlogReportUsersReport 来实现 DownloadableReport 接口,如下例所示。但是请注意,作为演示用途,我故意把 UsersReport

PHP에서 인터페이스 사용 🎜🎜🎜인터페이스는 OOP(객체 지향 프로그래밍) 코드 베이스의 중요한 부분입니다. 인터페이스를 사용하면 코드 결합을 줄이고 확장성을 높일 수 있습니다. 예를 들어 다음 클래스를 살펴보겠습니다. 🎜
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.'];
    }
}
🎜보시다시피 문자열을 반환하는 함수가 포함된 클래스를 정의했습니다. 이런 방식으로 메소드의 동작을 정의하므로 getName()이 문자열을 반환하는 방법을 알 수 있습니다. 그러나 다른 클래스에서 이 메서드를 호출한다고 가정해 보겠습니다. 이 클래스는 문자열이 어떻게 구성되는지 신경 쓸 필요가 없으며 메서드가 콘텐츠를 반환하는지 여부에만 신경을 씁니다. 예를 들어, 다른 클래스에서 이 메서드를 호출하는 방법을 살펴보겠습니다. 🎜
class UsersReport implements DownloadableReport
{
    public function getName()
    {
        return ['Users Report'];
    }

    public function getData(): string
    {
        return 'The data for the report is here.';
    }
}
🎜 위 코드는 잘 작동하지만 이제 UsersReport 클래스에 사용자 보고서를 다운로드하는 기능을 추가한다고 가정해 보겠습니다. . 물론 ReportDownloadService의 기존 메소드는 해당 메소드가 BlogReport 클래스로만 전달될 수 있도록 강제했기 때문에 사용할 수 없습니다. 따라서 원래 다운로드 방법의 이름을 수정하고(이름 중복을 피하기 위해) 아래와 같이 유사한 방법을 추가해야 합니다. 🎜
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.'];
    }
}
🎜 위 방법의 다운로드 파일 부분(주석 처리된 부분)이 다음을 사용한다고 가정합니다. 동일한 코드를 사용하며 이러한 동일한 코드를 별도의 메서드에 작성할 수 있지만 여전히 일부 반복되는 코드가 있습니다(번역자 참고: 각 메서드에 $name = $ report->getName();) 거의 동일한 클래스의 항목이 여러 개 있습니다. 이로 인해 향후 코드 확장이나 테스트를 위한 추가 작업이 발생할 수 있습니다. 🎜🎜예를 들어 새 <code>AnalyticsReport를 생성했다고 가정해 보겠습니다. 이제 해당 클래스에 새 downloadAnalyticsReportPDF() 메서드를 추가해야 합니다. 이 파일이 어떻게 확장되는지 명확하게 볼 수 있습니다. 이는 인터페이스를 사용하기 위한 완벽한 시나리오입니다! 🎜🎜첫 번째 인터페이스를 만드는 것부터 시작하겠습니다. 이름을 DownloadableReport로 지정하고 다음과 같이 정의하겠습니다. 🎜
class ReportDownloadService
{
    public function downloadReportPDF(DownloadableReport $report)
    {
        $name = $report->getName();

        // 下载文件……
    }

}
🎜이제 BlogReportUsersReport 를 업데이트할 수 있습니다. > 다음 예와 같이 DownloadableReport 인터페이스를 구현합니다. 하지만 시연을 위해 의도적으로 UsersReport에 코드를 잘못 작성했습니다. 🎜rrreeerrreee🎜 하지만 코드를 실행하려고 하면 다음과 같은 이유로 오류가 발생합니다. 🎜
  • 缺少 getHeaders() 方法.

  • getName() 方法不包括接口的方法签名中定义的返回类型。

  • getData() 方法定义了一个返回类型,但它与接口的方法签名中定义的类型不同。

因此,为了修复 UsersReport 使其正确实现 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.'];
    }
}

现在两个报告类都实现了相同的接口,我们可以这样更新我们的 ReportDownloadService

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

        // 下载文件……
    }

}

我们现在可以把 UsersReportBlogReport 对象传入 downloadReportPDF 方法中,而且不会出现任何错误。这是因为我们知道该对象实现了报告类的必要方法,并且将返回我们期望的数据类型。

通过向方法传递了一个接口,而不是一个具体的类,我们可以根据方法的实际作用(而不是方法的实现原理)来解耦 ReportDownloadService类和这些报告类。

如果我们想创建一个新的 AnalyticsReport,我们可以让它实现相同的接口。这样一来,我们不必添加任何新的方法,只需要将报告对象传递给同一个的 downloadReportPDF() 方法。如果你正在构建你自己的包或框架,接口可能对你特别有用。你只需要告诉使用者要实现哪个接口,然后他们就可以创建自己的类。例如,在 Laravel 中,我们可以通过实现 Illuminate\Contracts\Cache\Store 接口来创建自己的自定义缓存驱动类。

除了能改进代码之外,我喜欢使用接口的另一个原因是 —— 它们起到了“代码即文档”的作用。例如,如果我想弄清楚一个类能做什么,不能做什么,我倾向于先看接口,然后再看实现它的类。接口能够告诉我们所有可被调用的方法,而不需要我们过多地关心这些方法的底层实现方式是怎样的。

值得注意的是,Laravel 中的“契约(contract)”和“接口(interface)”这两个词语是可互换的。根据 Laravel 文档,“契约是一组由框架提供的核心服务的接口”。所以,记住:契约是一个接口,但接口不一定是契约。通常情况下,契约只是框架提供的一个接口。关于使用契约的更多信息,我建议大家可以阅读这一篇文档。它很好地剖析了契约究竟是什么,也对使用契约的方式与场景做了一定的叙述。

小结

希望通过阅读这篇文章,你能对什么是接口、如何在 PHP 中使用接口以及使用接口的好处有一个简单的了解。

原文地址:https://dev.to/ashallendesign/using-interfaces-to-write-better-php-code-391f

原文作者:Ash Allen

译者:kamly、jaredliw

推荐学习:《PHP视频教程

위 내용은 인터페이스란 무엇입니까? PHP의 인터페이스를 사용하여 우아한 코드를 작성하는 방법은 무엇입니까?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 juejin.cn에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제