PHP 常用设计模式
PHP 常用设计模式
设计模式是写好代码的经验总结,常用的几种要掌握。
1. 单例模式
整个项目只有一个实例,比如数据库连接。
class Db
{
private static $instance = null;
private function __construct() {}
public static function getInstance()
{
if (self::$instance === null) {
self::$instance = new self();
}
return self::$instance;
}
}
$db = Db::getInstance();
2. 工厂模式
根据参数创建不同的对象。
class Factory
{
public static function make($type)
{
$class = ucfirst($type);
return new $class();
}
}
$user = Factory::make('user');
$order = Factory::make('order');
3. 观察者模式
一个对象状态变化,通知所有观察者。
interface Observer
{
public function update($event);
}
class Event
{
private $observers = [];
public function add(Observer $observer)
{
$this->observers[] = $observer;
}
public function trigger($event)
{
foreach ($this->observers as $ob) {
$ob->update($event);
}
}
}
4. 常用场景
- 单例: 数据库、日志、配置
- 工厂: 创建不同类的对象
- 观察者: 事件触发、消息通知
- 策略: 不同支付方式
- 适配器: 兼容不同接口
5. 设计原则
- 单一职责:一个类只做一件事
- 开闭原则:对扩展开放,对修改关闭
- 依赖倒置:依赖抽象不依赖具体
总结
PHP 常用设计模式要点:
- 单例模式:只创建一个实例
- 工厂模式:统一创建对象
- 观察者:事件通知
- 理解设计原则
- 不要为了模式而模式
设计模式是工具,解决问题才是目的。
PHP 常用设计模式
PHP 常用设计模式
设计模式不是玄学,是前人踩坑总结出来的套路。这篇讲 PHP 开发中最常用的几个。
1. 单例模式(最常用)
保证一个类只有一个实例,节省资源。
class Database
{
private static $instance = null;
private $pdo;
// 构造函数私有化,禁止外部 new
private function __construct()
{
$this->pdo = new PDO('mysql:host=127.0.0.1;dbname=blog', 'root', '123456');
}
// 禁止克隆
private function __clone() {}
public static function getInstance()
{
if (self::$instance === null) {
self::$instance = new self();
}
return self::$instance;
}
public function query($sql)
{
return $this->pdo->query($sql);
}
}
// 使用
$db = Database::getInstance();
$db->query("SELECT * FROM users");
适用场景: 数据库连接、日志类、配置类。
2. 工厂模式
根据参数创建不同对象,不用直接 new。
interface Logger
{
public function write($message);
}
class FileLogger implements Logger
{
public function write($message)
{
file_put_contents('log.txt', $message . "\n", FILE_APPEND);
}
}
class DatabaseLogger implements Logger
{
public function write($message)
{
// 写入数据库
}
}
class LoggerFactory
{
public static function create($type)
{
switch ($type) {
case 'file':
return new FileLogger();
case 'database':
return new DatabaseLogger();
default:
throw new Exception("不支持的日志类型");
}
}
}
// 使用
$logger = LoggerFactory::create('file');
$logger->write("这是一条日志");
3. 观察者模式
对象状态变化时自动通知依赖它的对象。
interface Observer
{
public function update($event);
}
class Order
{
private $observers = [];
public function addObserver(Observer $observer)
{
$this->observers[] = $observer;
}
public function pay()
{
// 支付逻辑
echo "订单支付成功\n";
// 通知所有观察者
foreach ($this->observers as $observer) {
$observer->update('pay_success');
}
}
}
class SendSmsObserver implements Observer
{
public function update($event)
{
if ($event == 'pay_success') {
echo "发送支付成功短信\n";
}
}
}
class SendEmailObserver implements Observer
{
public function update($event)
{
if ($event == 'pay_success') {
echo "发送支付成功邮件\n";
}
}
}
// 使用
$order = new Order();
$order->addObserver(new SendSmsObserver());
$order->addObserver(new SendEmailObserver());
$order->pay();
适用场景: 事件系统、消息通知。
4. 策略模式
定义一系列算法,让它们可以互相替换。
interface PayStrategy
{
public function pay($amount);
}
class AlipayStrategy implements PayStrategy
{
public function pay($amount)
{
echo "支付宝支付 {$amount} 元\n";
}
}
class WechatPayStrategy implements PayStrategy
{
public function pay($amount)
{
echo "微信支付 {$amount} 元\n";
}
}
class OrderPay
{
private $strategy;
public function setStrategy(PayStrategy $strategy)
{
$this->strategy = $strategy;
}
public function pay($amount)
{
$this->strategy->pay($amount);
}
}
// 使用
$orderPay = new OrderPay();
$orderPay->setStrategy(new AlipayStrategy());
$orderPay->pay(100);
总结
常用设计模式就这几个:
- 单例模式: 全局唯一对象(数据库连接)
- 工厂模式: 统一创建对象
- 观察者模式: 事件通知
- 策略模式: 算法切换
设计模式不是为了用而用,是解决特定问题的。项目小就别硬套,过度设计比没有设计更糟。
PHP 设计模式:单例、工厂、观察者实战详解
前言
设计模式不是八股文,它是前人踩坑踩出来的最佳实践。PHP 开发中最常用的三个设计模式:单例、工厂、观察者。本文用最直白的方式讲清楚。
一、单例模式(Singleton)
什么时候用
全局只需要一个实例的对象,比如:
- 数据库连接
- 配置管理
- 日志对象
代码实现
<?php
class Database
{
private static $instance = null;
private $conn;
// 构造函数私有化,防止外部 new
private function __construct()
{
$this->conn = mysqli_connect('localhost', 'user', 'pass', 'db');
}
// 禁止克隆
private function __clone() {}
// 禁止反序列化
public function __wakeup()
{
throw new Exception("不能反序列化单例");
}
public static function getInstance()
{
if (self::$instance === null) {
self::$instance = new self();
}
return self::$instance;
}
public function getConnection()
{
return $this->conn;
}
}
// 使用
$db = Database::getInstance();
$conn = $db->getConnection();
为什么要私有化构造函数
如果构造函数是 public 的,外面就能 new Database(),那就不是单例了。
二、工厂模式(Factory)
什么时候用
需要根据不同条件创建不同对象的时候,比如:
- 根据支付类型创建不同的支付对象(微信、支付宝、银行卡)
- 根据数据库类型创建不同的数据库对象(MySQL、Redis)
简单工厂
<?php
interface Payment
{
public function pay($amount);
}
class WechatPay implements Payment
{
public function pay($amount)
{
echo "微信支付 {$amount} 元";
}
}
class Alipay implements Payment
{
public function pay($amount)
{
echo "支付宝支付 {$amount} 元";
}
}
class PaymentFactory
{
public static function make($type)
{
switch ($type) {
case 'wechat':
return new WechatPay();
case 'alipay':
return new Alipay();
default:
throw new Exception("不支持的支付方式");
}
}
}
// 使用
$pay = PaymentFactory::make('wechat');
$pay->pay(100);
工厂模式的好处
- 解耦:客户端不需要知道具体怎么创建对象
- 易扩展:新增支付方式只需要加一个类和工厂里的一个 case
- 统一管理:所有对象的创建都在工厂里,方便维护
三、观察者模式(Observer)
什么时候用
一个对象状态改变时,需要通知多个其他对象,比如:
- 用户注册后:发邮件、发短信、送积分
- 订单状态变更后:通知仓库、通知物流、通知客服
代码实现
<?php
// 事件接口
interface Observer
{
public function update($eventData);
}
// 事件主体
class Event
{
private $observers = [];
public function attach(Observer $observer)
{
$this->observers[] = $observer;
}
public function trigger($eventData)
{
foreach ($this->observers as $observer) {
$observer->update($eventData);
}
}
}
// 具体观察者
class SendEmail implements Observer
{
public function update($eventData)
{
echo "发送邮件给 {$eventData['email']}\n";
}
}
class SendSms implements Observer
{
public function update($eventData)
{
echo "发送短信给 {$eventData['phone']}\n";
}
}
class GivePoints implements Observer
{
public function update($eventData)
{
echo "给用户送 100 积分\n";
}
}
// 使用
$event = new Event();
$event->attach(new SendEmail());
$event->attach(new SendSms());
$event->attach(new GivePoints());
// 用户注册,触发事件
$event->trigger([
'email' => 'user@example.com',
'phone' => '13800138000'
]);
观察者模式的好处
- 解耦:事件主体不需要知道谁在监听
- 易扩展:新增监听者只需要加一个类,不需要改原来的代码
- 符合开闭原则:对扩展开放,对修改关闭
四、什么时候用什么模式
| 场景 | 用什么模式 |
|---|---|
| 全局只需要一个实例 | 单例 |
| 根据条件创建不同对象 | 工厂 |
| 一个动作触发多个后续操作 | 观察者 |
五、常见坑
- 单例用太多:单例用多了会变成全局变量,代码难维护
- 工厂过度设计:简单逻辑就别硬上工厂,会增加复杂度
- 观察者滥用:所有操作都做成观察者,调试会很痛苦
总结
设计模式是工具,不是目的。
- 单例:保证全局只有一个实例
- 工厂:统一管理对象创建
- 观察者:一个事件,多个响应
用对了让代码更清晰,用错了让代码更复杂。记住:先解决问题,再考虑模式。