PHP设计模式应在代码重复、难改时引入,单例仅适用于全局唯一资源且需按运行环境区分:PHP-FPM中限单请求内有效,Swoole中需进程同步;工厂核心是收口创建逻辑而非简单封装new;策略模式要求算法纯函数式、接口统一、可替换,避免if-else伪装。

PHP设计模式不是“用了就高级”,而是当某段代码开始出现重复、难改、不敢动时,它才真正该出场。直接上手写单例或工厂,八成是提前给自己挖坑。
单例模式只在「全局唯一资源」场景下成立
很多人一上来就给日志类、配置类套 Singleton,结果发现每次请求都新建一个实例——因为在 PHP-FPM 模式下,每个请求是独立进程,static 变量根本跨不了请求。真要管住“唯一”,得看运行环境:
- PHP-FPM:单例只在单次请求内有效,适合封装数据库连接(避免同个请求里反复 new PDO)
- Swoole/Workerman:常驻内存,
static实例会跨请求存活,此时必须加锁或用swoole_table做进程间同步 - 别把
__construct里做耗时初始化(比如读配置文件)当成理所当然——懒加载没错,但首次调用卡 200ms 就得反思是不是该预热
典型错误:getInstance() 没判空就直接 new,或忘了禁用 __clone 和 __wakeup,导致反序列化后绕过单例控制。
工厂模式不是“new 的集合”,而是「创建逻辑的收口」
当你在控制器里看到三处 new WechatPay()、两处 new Alipay()、还有一处硬编码的 if ($type === 'wechat') {...},这才是工厂该介入的信号。重点不在“封装 new”,而在“把分支判断从业务逻辑里拎出来”:
立即学习“PHP免费学习笔记(深入)”;
- 工厂类本身不该包含支付逻辑,只负责返回符合
PaymentInterface的对象 - 参数别用字符串直传(如
create('alipay')),改用枚举类或配置键名,避免拼错白跑半天 - 如果工厂方法里开始出现 if-else 嵌套三层以上,说明职责过重——该拆成抽象工厂(
PaymentFactory+RefundFactory)或引入策略模式
示例陷阱:UserFactory::createUser($data) 里既处理用户属性赋值,又连带初始化头像上传、发欢迎邮件——这已经越界成服务类了。
策略模式落地的关键是「让算法可插拔,而非可配置」
很多项目把策略写成一堆 if ($rule === 'vip') { ... } elseif ($rule === 'promo') { ... },再包一层 RuleStrategy 类,这不叫策略模式,这叫 if-else 换了个马甲。真正的落地点是:
- 每个策略类必须实现统一接口(如
DiscountStrategy),且方法签名完全一致(参数类型、返回类型不能靠文档约定) - 上下文(
ShoppingCart)不关心具体策略是谁,只调$this->strategy->apply($price)——换策略只需改构造注入,不碰任何业务分支 - 策略类内部禁止访问全局变量、静态方法或 DB 连接——它应该是纯函数式的,输入确定,输出确定,方便单元测试
常见翻车点:策略类里偷偷调 Config::get('discount.vip.rate'),导致测试时无法 mock 配置;或者策略之间互相依赖,破坏了“可替换”前提。
最易被忽略的是组合场景:比如一个订单既要选支付策略,又要选优惠策略,还要选通知策略——这时候单个工厂或单个策略接口撑不住,得用组合+依赖注入,而不仅仅是堆 class。



















