PHP项目里有哪些设计模式

wen PHP项目 1

PHP项目里有哪些设计模式?——从实战角度拆解最常用的10种模式(附代码示例)

目录导读

  1. 为什么PHP开发者必须掌握设计模式?
  2. 创建型模式:单例、工厂、抽象工厂
  3. 结构型模式:适配器、装饰器、门面
  4. 行为型模式:策略、观察者、模板方法、责任链
  5. 如何在Laravel/ThinkPHP中识别这些模式?
  6. 常见问题FAQ(Q&A)
  7. 选择模式的黄金法则

为什么PHP开发者必须掌握设计模式?

在PHP开发中,设计模式不是“炫技”,而是解决代码复用性、可维护性、扩展性的经典方案,根据Stack Overflow 2024年调查,PHP仍是Web后端的主力语言(占78%),而Laravel、Symfony等框架内部大量使用了设计模式。

PHP项目里有哪些设计模式

实战场景:你写了一个订单类,突然要增加“支付宝支付”和“微信支付”,如果直接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:记住三个关键词——创建对象找工厂/单例,组合对象找适配器/装饰器,交互对象找策略/观察者


选择模式的黄金法则

  1. 不要为了模式而模式,先写简单代码,当出现“三个if-else分支添加新功能”时再重构。
  2. 优先使用框架内置模式(比如Laravel的容器),而不是自己造轮子。
  3. 组合使用:工厂+策略+装饰器是PHP项目最常见的黄金组合。
  4. 关注SOLID原则:设计模式是实现SOLID的工具,而不是目的。

最后给PHP开发者的建议:从“单例==数据库”这个经典案例入手,逐步在真实业务中引入策略(支付、运费)和观察者(通知、日志),设计模式不是背出来的,是在多次重构后“痛”出来的。

如果觉得本文有用,欢迎收藏转发,下一期将深度拆解“Laravel中的门面模式如何绕过构造器注入”,敬请期待。

抱歉,评论功能暂时关闭!