PHP项目里有哪些设计模式?——从实战角度拆解最常用的10种模式(附代码示例)
目录导读
- 为什么PHP开发者必须掌握设计模式?
- 创建型模式:单例、工厂、抽象工厂
- 结构型模式:适配器、装饰器、门面
- 行为型模式:策略、观察者、模板方法、责任链
- 如何在Laravel/ThinkPHP中识别这些模式?
- 常见问题FAQ(Q&A)
- 选择模式的黄金法则
为什么PHP开发者必须掌握设计模式?
在PHP开发中,设计模式不是“炫技”,而是解决代码复用性、可维护性、扩展性的经典方案,根据Stack Overflow 2024年调查,PHP仍是Web后端的主力语言(占78%),而Laravel、Symfony等框架内部大量使用了设计模式。

实战场景:你写了一个订单类,突然要增加“支付宝支付”和“微信支付”,如果直接if-else堆代码,三个月后你连自己都看不懂,而策略模式+工厂模式能让新支付方式在5分钟内接入,且不污染原有逻辑。
核心价值:降低耦合度、提升代码可读性、便于单元测试。
创建型模式:让对象“听话地”诞生
单例模式(Singleton)
用途:数据库连接、缓存实例、日志写入器,确保全局只存在一个对象。
class Database {
private static ?Database $instance = null;
private function __construct() { /* 私有构造 */ }
public static function getInstance(): Database {
if (self::$instance === null) {
self::$instance = new self();
}
return self::$instance;
}
}
注意:PHP的new self()在单例中不受构造函数限制,但需配合private __clone()防止克隆。
工厂模式(Factory)
用途:根据参数动态创建不同类对象,隐藏new的细节。
class PaymentFactory {
public static function create(string $type): PaymentInterface {
return match($type) {
'alipay' => new Alipay(),
'wechat' => new WechatPay(),
default => throw new InvalidArgumentException("无此支付类型"),
};
}
}
优势:客户端无需知道具体类名,只需传字符串。
抽象工厂模式(Abstract Factory)
区别:工厂模式针对“一种产品”,抽象工厂针对“一系列相关产品”,比如做跨平台UI组件(Windows按钮+Windows输入框,Mac按钮+Mac输入框)。
interface UIFactory {
public function createButton(): Button;
public function createInput(): Input;
}
class WindowsFactory implements UIFactory { /* 返回Win风格组件 */ }
何时用:项目需要支持多套主题或多种数据库驱动(MySQL+PostgreSQL)。
结构型模式:让类与类“组队”协作
适配器模式(Adapter)
场景:现有老的Mailer类方法叫sendMail($to, $content),新框架要求统一send($to, $content)接口。
class LegacyMailerAdapter implements MailInterface {
public function __construct(private LegacyMailer $legacy) {}
public function send(string $to, string $content): bool {
return $this->legacy->sendMail($to, $content);
}
}
典型应用:对接第三方SDK时,统一你的业务接口。
装饰器模式(Decorator)
场景:给日志增加“时间戳”、“加密”、“压缩”功能,但不能改原类。
interface Logger { public function log(string $msg); }
class TimeDecorator implements Logger {
public function __construct(private Logger $logger) {}
public function log(string $msg) {
$this->logger->log('['.date('Y-m-d H:i:s').'] '.$msg);
}
}
// 调用:$logger = new TimeDecorator(new FileLogger());
优势:叠加功能就像堆乐高,且符合开闭原则。
门面模式(Facade)
场景:一个“下单”功能需要操作库存、订单、优惠券三个子系统,门面提供一个统一入口。
class OrderFacade {
public function placeOrder(array $data) {
(new StockService())->reduce($data['sku']);
(new OrderService())->create($data);
(new CouponService())->use($data['coupon_id']);
}
}
典型框架:Laravel的DB::、Cache::就是门面,静态调用背后是复杂组件。
行为型模式:让对象“默契”沟通
策略模式(Strategy)
场景:运费计算有多重规则(按重量、按件数、满减),把每种算法封装成独立策略类。
interface ShippingStrategy {
public function calc(array $package): float;
}
class WeightStrategy implements ShippingStrategy { /* 按重量 */ }
class CountStrategy implements ShippingStrategy { /* 按件数 */ }
class ShippingContext {
public function __construct(private ShippingStrategy $strategy) {}
public function setStrategy(ShippingStrategy $strategy) { $this->strategy = $strategy; }
}
注意:策略模式解决“同一行为的不同实现”,而不是“状态切换”。
观察者模式(Observer)
场景:用户注册成功后,需要发送邮件、短信、推送通知,用观察者解耦。
class UserEvent {
private array $listeners = [];
public function attach(callable $fn) { $this->listeners[] = $fn; }
public function trigger(User $user) {
foreach ($this->listeners as $fn) { $fn($user); }
}
}
// 使用:$event->attach(function($user){ (new Mail())->send($user); });
框架实践:Laravel的Event + Listener就是原生观察者。
模板方法模式(Template Method)
场景:数据导入流程固定(读取文件→校验→清洗→入库),但每种文件类型处理细节不同。
abstract class DataImporter {
public function import(string $file): void {
$data = $this->readFile($file);
$this->validate($data);
$this->process($data);
$this->save($data);
}
abstract protected function readFile(string $file): array;
abstract protected function validate(array $data): void;
protected function process(array &$data) { /* 通用清洗 */ }
}
优点:骨架固定,子类只需实现差异部分。
责任链模式(Chain of Responsibility)
场景:一个敏感词过滤系统,需要依次检查“长度”、“非法词”、“政治敏感”,每个检查失败则终止。
abstract class Filter {
private ?Filter $next = null;
public function setNext(Filter $next): self { $this->next = $next; return $this; }
public function handle(string $content): bool {
if (!$this->check($content)) {
return false; // 不通过
}
return $this->next ? $this->next->handle($content) : true;
}
abstract protected function check(string $content): bool;
}
注意:与策略模式区别——责任链是“链式调优”,策略是“单一替代”。
如何在Laravel/ThinkPHP中识别这些模式?
| 框架 | 模式实例 |
|---|---|
Laravel的IoC容器 |
工厂模式+单例模式(app(ClassName::class)) |
| Laravel的中间件 | 责任链模式($next($request)) |
Laravel的Cache门面 |
门面模式 |
ThinkPHP的验证器 |
策略模式(不同验证规则类) |
| Symfony的事件调度器 | 观察者模式 |
进阶技巧:看框架源码时,先搜implements关键词,再找interface定义——几乎所有模式都基于接口。
常见问题FAQ(Q&A)
Q1:设计模式会让代码变啰嗦吗? A:初期会,但工程上“可维护性”永远优先于“行数短”,模式本质是“约定优于配置”,团队沟通成本更低。
Q2:什么时候不该用单例? A:依赖外部状态(比如每个请求有不同的用户上下文)时,单例会带来静态数据污染,PHP-FPM模式下,单例只在单个请求内生效,并非跨请求共享。
Q3:工厂模式和策略模式如何选择? A:工厂是“创建对象”时用,策略是“运行行为”时用,比如创建支付对象用工厂,而支付时的手续费计算用策略。
Q4:Laravel自带哪些设计模式? A:容器(工厂+反射)、门面、中间件(责任链)、事件(观察者)、服务提供者(单例+注册表)。
Q5:新手如何快速记忆? A:记住三个关键词——创建对象找工厂/单例,组合对象找适配器/装饰器,交互对象找策略/观察者。
选择模式的黄金法则
- 不要为了模式而模式,先写简单代码,当出现“三个if-else分支添加新功能”时再重构。
- 优先使用框架内置模式(比如Laravel的容器),而不是自己造轮子。
- 组合使用:工厂+策略+装饰器是PHP项目最常见的黄金组合。
- 关注SOLID原则:设计模式是实现SOLID的工具,而不是目的。
最后给PHP开发者的建议:从“单例==数据库”这个经典案例入手,逐步在真实业务中引入策略(支付、运费)和观察者(通知、日志),设计模式不是背出来的,是在多次重构后“痛”出来的。
如果觉得本文有用,欢迎收藏转发,下一期将深度拆解“Laravel中的门面模式如何绕过构造器注入”,敬请期待。