接口必须用 interface 声明,核心是契约约束而非复用;只声明 public 方法,禁用属性/构造函数;类型必须明确,避免 mixed/无声明;依赖抽象DTO而非框架类;按能力细粒度拆分接口。

接口类必须用 interface 声明,不能用 abstract class
PHP 接口的核心作用是契约约束,不是代码复用。用 abstract class 容易误塞具体实现(比如 protected 方法、属性或构造逻辑),破坏调用方对“纯行为约定”的预期。
实操建议:
-
interface中只允许声明public方法,不许有属性、构造函数、静态方法(PHP 8.1+ 允许static方法但需谨慎)、final或private修饰符 - 若需共享常量,可定义
interface并用const,但避免塞业务逻辑相关的默认值 - 多个接口组合时用
implements A, B, C,不要为“省事”而合并成一个大接口
方法签名要锁定参数类型和返回类型,尤其注意 void 和 mixed
没类型声明的接口等于没规范。调用方无法静态分析,IDE 补全失效,运行时才报错——这违背“统一调用”的初衷。
常见错误现象:
立即学习“PHP免费学习笔记(深入)”;
- 接口方法写
function handle($data),实现类却用function handle(array $data): array—— PHP 不报错但契约已断裂 - 返回类型用
mixed,导致调用方必须手动is_array()/is_object()判断,失去接口抽象价值 - 可空返回写成
?string,但实际实现可能返回null或抛异常,调用方无法预期
推荐写法:function execute(Request $request): Response,其中 Request 和 Response 是明确的 DTO 类,而非数组或 stdClass。
避免在接口中暴露框架或传输细节,比如 Illuminate\Http\Request
接口一旦依赖具体框架类,就锁死了实现方式。今天用 Laravel,明天想切到 Symfony 或 Swoole HTTP Server 就得重写全部实现,还可能引发循环依赖。
1 先进的多级用户及代理商管理功能 2 透明的会员资金管理,系统自动完成会员资金的管理业务。 3 规范的业务流程,客户提交订单--业务人员受理订单--技术人员开通业务,简单,规范,使用的企业管理更加规范化。 4 便捷安装接入,只要把你的前台链接到我们指定的入口,其它的业务管理全部由系统自动完成。 5 领先的产品及菜单管理功能。可对产品和会员的菜单进行动态的增加、修改、删除,从而使用轻松方便的增加新
正确做法:
- 定义薄层数据对象:如
class ServiceInput和class ServiceOutput,只含public属性 + 简单构造 - 让控制器/网关层负责把
Illuminate\Http\Request映射为ServiceInput,再传给接口实现 - 接口方法名聚焦业务动作,如
createOrder()、verifyPayment(),而非handlePostRequest()
接口粒度要细,按能力而非按服务模块拆分
一个叫 UserServiceInterface 的接口,如果包含 register()、login()、sendSmsCode()、updateProfile(),那它大概率会成为修改热点——每次加个短信渠道就得改这个接口,所有实现类被迫重写或打桩。
更可持续的方式:
-
UserRegistrationInterface:只管注册流程,含validate()、persist()、notify() -
UserAuthInterface:专注认证,含issueToken()、verifyCredentials() -
SmsGatewayInterface:与用户无关,只定义send(string $phone, string $message): bool
这样,换短信供应商只需新写一个 SmsGatewayInterface 实现,完全不影响用户注册逻辑。
真正难的是划清能力边界——别让“统一调用”变成“统一耦合”。接口不是分类目录,是能力契约。每多一个方法,就要问一句:这个动作是否必然被所有实现以相同语义执行?










