PHP类如何实现接口_PHP类实现接口语法【语法】

1次阅读

php类实现接口必须用implements关键字,不能用extends;类可继承一个父类再实现多个接口,方法签名须严格匹配,接口无属性但可定义public Static常量

PHP类如何实现接口_PHP类实现接口语法【语法】

PHP类实现接口必须用implements关键字

PHP里接口不是继承关系,不能用extends,必须用implements。这是最常写错的地方——尤其从Java或C#转过来的人,一顺手就写成class A extends B implements C,结果发现B是类、C是接口,语法直接报错:Cannot use 'C' as class name as it is reserved(如果接口名被误当类名解析)或者更常见的Parse Error: syntax error, unexpected 'implements'

正确写法只有一种:类可以extends一个父类,但所有接口都得跟在implements后面,多个接口用逗号分隔。

  • class User implements JsonSerializable, Loggable
  • class Admin extends User implements PermissionCheckable ✅(先继承,再实现)
  • class Guest extends User, Loggable ❌(,不能替代implements
  • class ApiClient implements ArrayAccess extends HttpClient ❌(extends不能放在implements之后)

接口方法必须全部实现,且签名严格匹配

PHP不会帮你补方法,也不会宽容参数类型或返回值的微小差异。只要接口里声明了public function save(String $data): bool,你实现时漏掉string类型声明、改成function save($data): int,或者把bool换成void,运行时就会报致命错误:Declaration of MyClass::save() must be compatible with MyInterface::save()

注意几个易忽略点:

立即学习PHP免费学习笔记(深入)”;

  • 接口中方法默认是public,实现类里不能降级为protectedprivate
  • PHP 8+ 开启严格模式后,return类型不匹配会直接报Fatal error,不是警告
  • 可选参数在接口中不允许出现——接口方法签名必须是“最小契约”,所有参数都算必填;实现类可以加默认值,但不能删参数
  • 如果接口方法带&$ref引用参数,实现类也必须带&,否则签名不一致

一个类可以实现多个接口,但不能重复实现同一接口

PHP允许class OrderProcessor implements Payable, Shippable, Notifiable,这很常见。但如果你通过trait引入了某个接口的实现,又在类声明里再次implements同一个接口,PHP会报错:Class OrderProcessor cannot implement previously implemented interface Payable

典型踩坑场景:

  • 父类已经implements Cacheable子类又写class RedisCache extends BaseCache implements Cacheable → 报错
  • 用了laravelInteractsWithQueue trait,它本身不实现接口,但你误以为它替你实现了ShouldQueue,结果忘了在类上显式implements ShouldQueue → 队列不生效,无报错但逻辑失效
  • 两个trait各自提供同名方法,且都声称“满足某接口”,但没真正实现接口契约 → 运行时报方法未实现错误,而不是trait冲突

接口不能有属性,但可以用const定义常量

接口里不能声明public $host = 'localhost'这类属性,但可以定义const。这些常量会被自动视为publicstatic,且不可覆盖。常量名在实现类中可通过self::STATUS_PENDINGMyInterface::STATUS_PENDING访问。

注意兼容性细节:

  • PHP 7.1+ 才支持接口中使用const,老版本会直接解析失败
  • 接口常量不能是数组(PHP 8.1+才支持array常量,但接口里仍不支持)
  • 别在接口里定义const VERSION = '1.0'然后指望子类能重写——它就是死的,改不了
  • 如果多个接口定义了同名常量(比如都叫MAX_RETRY),而一个类同时实现它们,不会冲突,但调用时必须用完整接口名限定,否则报ambiguous constant

接口本身不包含逻辑,也不参与实例化,它的作用就是划清“能做什么”的边界。很多人卡在“为什么写了implements却还报错”,问题往往不在语法,而在方法签名细节、继承链干扰或常量引用方式——这些地方没有运行时提示,只有报错那一刻才暴露。

text=ZqhQzanResources