What is an interface? How to use interfaces in PHP? This article will talk about using interfaces to write more elegant PHP code. I hope it will be helpful to you!
In programming, it is important to ensure that the code is readable, maintainable, extensible and easy to test; and using interfaces is precisely how we improve all these factors in the code One of the methods.
This article is intended for developers who have a basic understanding of OOP (Object-Oriented Programming) concepts and use inheritance in PHP. If you know how to use inheritance in PHP code, you should have a good understanding of this article.
In short, interfaces are simply descriptions of what a class should do, and they can be used to ensure that any class that implements the interface will include every public method defined within it.
Interfacecan:
Interfacecannot:
Interface is used to define the public methods that a class should include. Remember, you only need to define the signature of the method in the interface, and you do not need to include the body of the method (like you usually see methods in classes). **This is because interfaces are only used to define communication between objects, not to define communication and behavior like in a class. **To illustrate this problem, the following shows an example interface that defines several public methods:
interface DownloadableReport { public function getName(): string; public function getHeaders(): array; public function getData(): array; }
According to the php.net document, we can know that the interface has two main purposes:
Allows developers to create different classes of objects that can be used interchangeably because they implement the same interface or interfaces. Common examples include: multiple database access services, multiple payment gateways, different caching strategies, etc. Different implementations can be interchanged without requiring any modifications to the code that uses them.
Allows a function or method to accept parameters that conform to an interface and operate on them without caring about what else the object can do or how it is implemented. These interfaces are usually named Iterable
, Cacheable
, Renderable
, etc. to illustrate what these interfaces actually mean.
Interfaces are an important part of the OOP (Object Oriented Programming) code base. Interfaces allow us to reduce code coupling and increase scalability. For example, let's look at the following class:
class BlogReport { public function getName(): string { return 'Blog report'; } }
As you can see, we have defined a class with a function that returns a string. This way, we define the behavior of the method, so we know how getName()
returns a string. However, suppose we call this method in another class; this class does not need to care about how the string is constructed, it only cares about whether the method returns content. For example, let's see how to call this method in another class:
class ReportDownloadService { public function downloadPDF(BlogReport $report) { $name = $report->getName(); // 下载文件…… } }
Although the above code runs normally, let's imagine that we now want to add downloads to the UsersReport
class Features reported by users. Obviously, we cannot use the existing methods in ReportDownloadService
because we have enforced that the method can only be passed the BlogReport
class. Therefore, we must modify the name of the original download method (to avoid duplicate names), and then add a similar method, as shown below:
class ReportDownloadService { public function downloadBlogReportPDF(BlogReport $report) { $name = $report->getName(); // 下载文件…… } public function downloadUsersReportPDF(UsersReport $report) { $name = $report->getName(); // 下载文件…… } }
Assume that the download file part of the above method ( The commented out part) uses the same code, and we can write these same codes into a separate method, but we will still have some repeated code (Translator's Note: Refers to the in each method $name = $report->getName();
) and there are multiple entries of almost identical classes. This may create additional work for extending the code or testing in the future.
For example, suppose we create a new AnalyticsReport
; we now need to add a new downloadAnalyticsReportPDF()
method to that class. You can clearly see how this file will expand. This is a perfect scenario for using interfaces!
Let's start by creating the first interface: Let's name it DownloadableReport
and define it as follows:
interface DownloadableReport { public function getName(): string; public function getHeaders(): array; public function getData(): array; }
We can now update BlogReport
and UsersReport
to implement the DownloadableReport
interface, as shown in the following example. But please note that for demonstration purposes, I intentionally wrote the code in UsersReport
wrong:
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.'; } }
But when we try to run the code, we will receive an error for the following reasons :
缺少 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(); // 下载文件…… } }
我们现在可以把 UsersReport
或 BlogReport
对象传入 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视频教程》
The above is the detailed content of What is an interface? How to write elegant code using interfaces in PHP?. For more information, please follow other related articles on the PHP Chinese website!