适配器模式在PHP中需手动桥接不兼容接口,不能仅靠实现同一接口;必须显式注入被适配对象、实现目标接口、仅做参数转换等薄层适配,且注意自动加载配置与类型安全。
适配器模式在 PHP 中不是靠“实现接口”就能自动生效的
PHP 的接口(
)只约束方法签名,不提供行为转换能力。所谓“适配”,本质是手动桥接两个不兼容的接口或类——比如老代码用
,新邮件服务只接受
。这时候不能靠改接口定义来“兼容”,得写一个中间类把调用转过去。
常见错误是以为只要让新旧类都实现同一个
就算完成适配,结果发现老逻辑传参方式根本进不去新实现里。
适配器必须显式接收被适配对象(如老类实例),并在自己方法中调用它
适配器自身要实现目标接口(如新系统期望的
),否则无法注入或替换
不要试图在适配器里重写业务逻辑,只做参数重组、返回值包装、异常转换等薄层转换
写一个标准适配器类:注意构造函数参数和方法委托
以适配旧版
到新版
为例。关键点不在“有没有 interface”,而在“谁负责创建旧对象”和“怎么传参”。
这里容易踩坑的是:
必须由外部传入(DI 容器或手动 new),不能在适配器里自己 new——否则就失去替换灵活性;
方法体内不做额外判断或格式化,那是
类该干的事。
立即学习
“
PHP免费学习笔记(深入)
”;
PHP 8.5.5
PHP 8.5.5 是 PHP 8.5 分支的维护更新版本。该版本延续了“小步快跑”的迭代逻辑,通过深度错误修复、底层性能微调以及安全加固,旨在为开发者提供一个更健壮、更高效的运行环境。该版本严格遵守语义化版本规范,不包含破坏性变更。
下载
类型提示冲突时,用 DTO 或封装类绕过 strict 检查
当旧类方法返回
,而新接口要求返回
,直接强转会报错,且破坏类型安全。这时别硬 cast,而是封装一层轻量 DTO。
新建
类,构造时接收原始
,提供
等方法
适配器的
返回这个 wrapper 实例,而不是试图伪造
实现
如果下游强依赖
,再写一个继承自
的子类,仅用于测试或过渡期
硬塞
到 wrapper 里,却只实现部分方法,会在运行时触发 “Call to undefined method” 错误,比类型不匹配更难排查。
Composer 自动加载与命名空间对适配器可见性的影响
适配器类如果放在
下但未在
的
中声明 PSR-4 映射,会导致
。这不是逻辑问题,是加载失败。
检查
是否包含:
确认文件路径为
,且命名空间是
运行
,尤其在新增类后忘记执行这步,会卡住半天
很多团队把适配器扔进
目录下随意命名,结果上线后因 autoloader 缓存没刷新,生产环境报错而本地正常——这种环境差异最消耗调试时间。
interfacesendEmail($to, $subject, $body)send(Message $msg)MailSenderInterfaceMessageSenderInterfaceLegacyMailerMessageSenderInterfaceclass LegacyMailerAdapter implements MessageSenderInterface
{
private LegacyMailer $legacy;
public function __construct(LegacyMailer $legacy)
{
$this->legacy = $legacy;
}
public function send(Message $message): bool
{
// 把 Message 对象拆成三个字符串参数,推给旧类
return $this->legacy->sendEmail(
$message->getTo(),
$message->getSubject(),
$message->getBody()
);
}
}$legacysend()MessagearrayResponseInterfaceLegacyResponseWrapperarraygetStatusCode()send()ResponseInterfaceResponseInterfaceSymfonyComponentHttpFoundationResponseimplements ResponseInterfacesrc/Adapter/composer.json"autoload"Class 'AppAdapterLegacyMailerAdapter' not foundcomposer.json"App\": "src/"src/Adapter/LegacyMailerAdapter.phpAppAdaptercomposer dump-autoloadapp/