本文目录导读:

- 策略模式(Strategy Pattern)
- 策略接口 + 闭包/回调
- 命令模式(Command Pattern)
- 表驱动方法(Table-Driven)
- 基于注解/属性(PHP 8+)
- 简单实用场景 - 提前返回
- 选择建议
在 PHP 中抽象分支有多种方式,我从简单到复杂给你介绍几种常用方法:
策略模式(Strategy Pattern)
这是最经典的分支抽象方式:
<?php
// 定义策略接口
interface PaymentStrategy {
public function pay(float $amount): string;
}
// 具体策略实现
class AlipayStrategy implements PaymentStrategy {
public function pay(float $amount): string {
return "使用支付宝支付:{$amount}元";
}
}
class WechatPayStrategy implements PaymentStrategy {
public function pay(float $amount): string {
return "使用微信支付:{$amount}元";
}
}
class BankCardStrategy implements PaymentStrategy {
public function pay(float $amount): string {
return "使用银行卡支付:{$amount}元";
}
}
// 上下文类
class PaymentContext {
private $strategy;
public function __construct(PaymentStrategy $strategy) {
$this->strategy = $strategy;
}
public function setStrategy(PaymentStrategy $strategy) {
$this->strategy = $strategy;
}
public function executePayment(float $amount): string {
return $this->strategy->pay($amount);
}
}
// 工厂类(可选)
class PaymentFactory {
public static function create(string $type): PaymentStrategy {
return match($type) {
'alipay' => new AlipayStrategy(),
'wechat' => new WechatPayStrategy(),
'bank' => new BankCardStrategy(),
default => throw new \InvalidArgumentException("未知支付方式: {$type}")
};
}
}
// 使用示例
$payment = new PaymentContext(PaymentFactory::create($_POST['method']));
echo $payment->executePayment(100);
策略接口 + 闭包/回调
PHP 的函数式特性让分支抽象更简洁:
<?php
class PriceCalculator {
private $rules = [];
// 注册价格计算规则
public function addRule(string $type, callable $calculator): void {
$this->rules[$type] = $calculator;
}
public function calculate(string $type, float $price): float {
if (!isset($this->rules[$type])) {
throw new \LogicException("未定义的规则类型: {$type}");
}
return ($this->rules[$type])($price);
}
}
// 使用示例
$calculator = new PriceCalculator();
$calculator->addRule('normal', function($price) {
return $price;
});
$calculator->addRule('discount', function($price) {
return $price * 0.8; // 8折
});
$calculator->addRule('vip', function($price) {
return $price * 0.6; // 6折
});
// 动态添加规则
$calculator->addRule('seasonal', function($price) {
return $price * 0.7 - 50; // 7折并减50
});
echo $calculator->calculate('vip', 100); // 输出 60
命令模式(Command Pattern)
用于需要解耦调用者和执行者的场景:
<?php
interface Command {
public function execute(): mixed;
}
class UserCreateCommand implements Command {
public function __construct(private array $data) {}
public function execute(): mixed {
// 创建用户的业务逻辑
return "创建用户: " . $this->data['name'];
}
}
class UserUpdateCommand implements Command {
public function __construct(private int $id, private array $data) {}
public function execute(): mixed {
// 更新用户的业务逻辑
return "更新用户 #{$this->id}";
}
}
class UserDeleteCommand implements Command {
public function __construct(private int $id) {}
public function execute(): mixed {
// 删除用户的业务逻辑
return "删除用户 #{$this->id}";
}
}
// 命令执行器
class CommandInvoker {
public function run(Command $command): mixed {
return $command->execute();
}
}
// 命令工厂
class CommandFactory {
public static function make(string $action, array $params): Command {
return match($action) {
'create' => new UserCreateCommand($params),
'update' => new UserUpdateCommand($params['id'], $params['data']),
'delete' => new UserDeleteCommand($params['id']),
default => throw new \InvalidArgumentException("未知操作")
};
}
}
$invoker = new CommandInvoker();
$command = CommandFactory::make('create', ['name' => '张三']);
$result = $invoker->run($command);
表驱动方法(Table-Driven)
适用于规则明确且可能比较多的情况:
<?php
class RouteHandler {
private $routes = [];
public function register(array $routes): void {
$this->routes = array_merge($this->routes, $routes);
}
public function handle(string $route, array $params): mixed {
if (!isset($this->routes[$route])) {
throw new \LogicException("路由不存在: {$route}");
}
$handler = $this->routes[$route];
// 处理不同的处理器类型
if (is_callable($handler)) {
return $handler($params);
}
if (is_string($handler) && str_contains($handler, '@')) {
[$class, $method] = explode('@', $handler);
$instance = new $class();
return $instance->$method($params);
}
if (is_array($handler)) {
[$class, $method] = $handler;
$instance = new $class();
return $instance->$method($params);
}
throw new \InvalidArgumentException("非法路由处理方式");
}
}
// 路由表
$routes = [
'user.create' => 'UserController@create',
'user.update' => 'UserController@update',
'user.delete' => function($params) {
return "闭包处理删除逻辑: " . json_encode($params);
},
];
$router = new RouteHandler();
$router->register($routes);
// 动态处理
$result = $router->handle('user.create', ['name' => '李四']);
基于注解/属性(PHP 8+)
现代 PHP 支持属性,可以实现更优雅的抽象:
<?php
#[Attribute(Attribute::TARGET_METHOD)]
class Route {
public function __construct(public string $path) {}
}
#[Attribute(Attribute::TARGET_CLASS)]
class Controller {
public function __construct(public string $name) {}
}
#[Controller(name: 'user')]
class UserController {
#[Route('/user/list')]
public function list(): array {
return ['users' => []];
}
#[Route('/user/create')]
public function create(array $data): array {
return ['created' => true, 'data' => $data];
}
}
// 简单的属性路由器
class AttributeRouter {
public function dispatch(string $path): mixed {
$controllers = get_classes_with_attribute(Controller::class);
foreach ($controllers as $class) {
$reflection = new \ReflectionClass($class);
$methods = $reflection->getMethods();
foreach ($methods as $method) {
$attributes = $method->getAttributes(Route::class);
foreach ($attributes as $attribute) {
$route = $attribute->newInstance();
if ($route->path === $path) {
$instance = $class;
return $instance->{$method->getName()}($_POST);
}
}
}
}
throw new \RuntimeException("路由未找到: {$path}");
}
}
简单实用场景 - 提前返回
有时候最简单的方式反而最清晰:
<?php
function processOrder(Order $order): string {
// 逐步验证和提前返回
if ($order->isCancelled()) {
return '订单已取消';
}
if (!$order->hasStock()) {
return '库存不足';
}
if (!$order->hasValidCoupon()) {
return '优惠券无效';
}
// 主流程
$order->pay();
$order->ship();
return '订单处理成功';
}
选择建议
| 方法 | 适用场景 |
|---|---|
| 策略模式 | 算法/业务逻辑可选,需要扩展性 |
| 闭包/回调 | 动态规则,规则简单不复杂 |
| 命令模式 | 操作可回滚、需要队列、需要日志 |
| 表驱动 | 大量固定映射关系,路由分发 |
| 注意 | 永远优先考虑最简单的方案 |
实际项目中,建议结合使用,比如策略模式负责业务逻辑抽象,表驱动和闭包负责轻量处理,命令模式负责复杂操作。
过度设计也是一种反模式,合适的才最好。