千家信息网

如何用接口写高质量PHP代码

发表于:2025-02-02 作者:千家信息网编辑
千家信息网最后更新 2025年02月02日,本篇内容介绍了"如何用接口写高质量PHP代码"的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!概述在编码
千家信息网最后更新 2025年02月02日如何用接口写高质量PHP代码

本篇内容介绍了"如何用接口写高质量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代码"的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注网站,小编将为大家输出更多高质量的实用文章!

接口 方法 代码 报告 契约 相同 对象 例子 数据 文件 类型 开发 高质量 不同 内容 多个 字符 字符串 实例 文档 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 计算机软件开发设计论文 湖南数据软件开发有哪些 量子与网络安全 网络安全设备监控范围 交通行业网络安全培训方案 软件开发项目方面工作总结 连接数据库显示未设置属性 网络技术与应用前景怎么样 安徽学生少儿编程平台软件开发 学校网络安全管理小组 DAKI是哪个数据库的英文简称 数据库查询姓王两个字的人 富士康网络技术员是做什么的 易语言本地数据库 web应用数据库性能 搜索更多网络安全手抄 建设网络安全的强国意义 软件开发成本超支的原因 国内外数据库的发展 网络安全法简析 瑞庭网络技术重庆有限公司 应用程序和服务器通讯协议 软件开发产品和研发测试比例 如何知道服务器地图的种子 广东世纪互联网科技有限公司 网络安全法有下列行为 广达服务器主板开机按f1跳过 软件开发成功怎么投放 什么修改器可以改服务器 服务器虚拟化什么意思
0