本文目录导读:

我来详细介绍PHP状态机流转控制的实现方案。
基础状态机实现
简单状态机类
<?php
class StateMachine
{
private string $currentState;
private array $transitions = [];
private array $callbacks = [];
public function __construct(string $initialState)
{
$this->currentState = $initialState;
}
/**
* 定义状态转换
* [
* 'pending' => ['approved', 'rejected'],
* 'approved' => ['processing'],
* 'processing' => ['completed', 'failed']
* ]
*/
public function defineTransitions(array $transitions): void
{
$this->transitions = $transitions;
}
/**
* 尝试执行状态转换
*/
public function transition(string $newState): bool
{
if (!$this->canTransition($newState)) {
throw new \InvalidArgumentException(
"Cannot transition from {$this->currentState} to {$newState}"
);
}
$oldState = $this->currentState;
// 执行前置回调
$this->executeCallbacks('before', $oldState, $newState);
// 更新状态
$this->currentState = $newState;
// 执行后置回调
$this->executeCallbacks('after', $oldState, $newState);
return true;
}
/**
* 检查是否允许转换
*/
public function canTransition(string $newState): bool
{
if (!isset($this->transitions[$this->currentState])) {
return false;
}
return in_array($newState, $this->transitions[$this->currentState]);
}
/**
* 注册回调
*/
public function on(string $event, callable $callback): void
{
$this->callbacks[$event][] = $callback;
}
private function executeCallbacks(string $type, string $oldState, string $newState): void
{
$eventName = "$type: $oldState -> $newState";
if (isset($this->callbacks[$eventName])) {
foreach ($this->callbacks[$eventName] as $callback) {
call_user_func($callback, $oldState, $newState);
}
}
}
public function getCurrentState(): string
{
return $this->currentState;
}
}
实际业务场景示例
订单状态机
<?php
class OrderStateMachine
{
private StateMachine $stateMachine;
private array $orderData;
const STATE_PENDING = 'pending';
const STATE_PAID = 'paid';
const STATE_SHIPPED = 'shipped';
const STATE_COMPLETED = 'completed';
const STATE_CANCELLED = 'cancelled';
const STATE_REFUNDED = 'refunded';
public function __construct(array $orderData)
{
$this->orderData = $orderData;
$this->stateMachine = new StateMachine($orderData['status'] ?? self::STATE_PENDING);
$this->setupTransitions();
$this->setupCallbacks();
}
private function setupTransitions(): void
{
$this->stateMachine->defineTransitions([
self::STATE_PENDING => [
self::STATE_PAID,
self::STATE_CANCELLED
],
self::STATE_PAID => [
self::STATE_SHIPPED,
self::STATE_REFUNDED
],
self::STATE_SHIPPED => [
self::STATE_COMPLETED,
self::STATE_REFUNDED
],
self::STATE_COMPLETED => [
self::STATE_REFUNDED
],
self::STATE_CANCELLED => [],
self::STATE_REFUNDED => []
]);
}
private function setupCallbacks(): void
{
// 支付成功回调
$this->stateMachine->on(
"after: pending -> paid",
function ($old, $new) {
$this->processPayment();
}
);
// 发货回调
$this->stateMachine->on(
"after: paid -> shipped",
function ($old, $new) {
$this->processShipping();
}
);
// 完成订单回调
$this->stateMachine->on(
"after: shipped -> completed",
function ($old, $new) {
$this->completeOrder();
}
);
}
private function processPayment(): void
{
// 处理支付逻辑
echo "处理支付...\n";
// 记录支付时间
$this->orderData['paid_at'] = date('Y-m-d H:i:s');
}
private function processShipping(): void
{
echo "订单发货...\n";
$this->orderData['shipped_at'] = date('Y-m-d H:i:s');
}
private function completeOrder(): void
{
echo "完成订单...\n";
$this->orderData['completed_at'] = date('Y-m-d H:i:s');
}
public function pay(): void
{
$this->stateMachine->transition(self::STATE_PAID);
}
public function ship(): void
{
$this->stateMachine->transition(self::STATE_SHIPPED);
}
public function complete(): void
{
$this->stateMachine->transition(self::STATE_COMPLETED);
}
public function cancel(): void
{
$this->stateMachine->transition(self::STATE_CANCELLED);
}
public function getStatus(): string
{
return $this->stateMachine->getCurrentState();
}
public function canTransition(string $targetState): bool
{
return $this->stateMachine->canTransition($targetState);
}
}
// 使用示例
$order = [
'id' => 1,
'amount' => 199.00,
'status' => 'pending'
];
$orderStateMachine = new OrderStateMachine($order);
// 支付
if ($orderStateMachine->canTransition('paid')) {
$orderStateMachine->pay();
echo "当前状态: " . $orderStateMachine->getStatus() . "\n";
}
// 发货
if ($orderStateMachine->canTransition('shipped')) {
$orderStateMachine->ship();
echo "当前状态: " . $orderStateMachine->getStatus() . "\n";
}
// 完成
if ($orderStateMachine->canTransition('completed')) {
$orderStateMachine->complete();
echo "当前状态: " . $orderStateMachine->getStatus() . "\n";
}
高级状态机模式
带验证和事件驱动的状态机
<?php
abstract class AbstractStateMachine
{
protected string $currentState;
protected array $transitionRules = [];
protected array $eventListeners = [];
abstract protected function getTransitions(): array;
abstract protected function getInitialState(): string;
public function __construct()
{
$this->currentState = $this->getInitialState();
$this->transitionRules = $this->getTransitions();
}
public function apply(string $state): void
{
if (!$this->canTransition($state)) {
throw new \RuntimeException(
sprintf('Invalid state transition: %s -> %s', $this->currentState, $state)
);
}
$from = $this->currentState;
// guard logic (条件检查)
$guardResult = $this->checkGuard($state);
if (!$guardResult['allowed']) {
throw new \RuntimeException($guardResult['message']);
}
// 执行状态转换
$this->currentState = $state;
// 触发事件
$eventName = sprintf('%s_to_%s', $from, $state);
$this->triggerEvent($eventName);
// 日志记录
$this->logTransition($from, $state);
}
protected function canTransition(string $state): bool
{
$allowedStates = $this->transitionRules[$this->currentState] ?? [];
return in_array($state, $allowedStates);
}
protected function checkGuard(string $targetState): array
{
$guardMethod = 'guard_' . $this->currentState . '_' . $targetState;
if (method_exists($this, $guardMethod)) {
return $this->$guardMethod();
}
return ['allowed' => true, 'message' => ''];
}
protected function triggerEvent(string $eventName): void
{
if (isset($this->eventListeners[$eventName])) {
foreach ($this->eventListeners[$eventName] as $listener) {
call_user_func($listener, $this);
}
}
}
public function on(string $eventName, callable $callback): void
{
$this->eventListeners[$eventName][] = $callback;
}
protected function logTransition(string $from, string $to): void
{
// 记录转换日志到数据库
$logEntry = [
'from' => $from,
'to' => $to,
'timestamp' => date('Y-m-d H:i:s'),
'user' => $_SESSION['user_id'] ?? null
];
// 存储到日志表
// Log::info('State transition', $logEntry);
}
public function getCurrentState(): string
{
return $this->currentState;
}
public function getAvailableTransitions(): array
{
return $this->transitionRules[$this->currentState] ?? [];
}
}
// 工作流状态机示例
class WorkflowStateMachine extends AbstractStateMachine
{
private array $workflowData;
private array $permissions = [];
public function __construct(array $data = [])
{
$this->workflowData = $data;
parent::__construct();
}
protected function getInitialState(): string
{
return 'draft';
}
protected function getTransitions(): array
{
return [
'draft' => ['submitted', 'cancelled'],
'submitted' => ['in_review', 'rejected'],
'in_review' => ['approved', 'rejected', 'returned'],
'approved' => ['in_progress'],
'in_progress' => ['completed', 'cancelled'],
'completed' => [],
'cancelled' => [],
'rejected' => ['draft'],
'returned' => ['draft']
];
}
// Guard 方法示例 (条件控制)
protected function guard_draft_submitted(): array
{
if (empty($this->workflowData['description'])) {
return ['allowed' => false, 'message' => 'Description is required for submission'];
}
if ($this->workflowData['amount'] < 0) {
return ['allowed' => false, 'message' => 'Amount cannot be negative'];
}
return ['allowed' => true, 'message' => ''];
}
protected function guard_in_review_approved(): array
{
// 检查审批权限
if (!$this->hasPermission($_SESSION['user_id'], 'approve_workflow')) {
return ['allowed' => false, 'message' => 'No permission to approve'];
}
return ['allowed' => true, 'message' => ''];
}
private function hasPermission($userId, $permission): bool
{
// 实现权限检查逻辑
return in_array($permission, $this->permissions[$userId] ?? []);
}
public function setWorkflowData(array $data): void
{
$this->workflowData = $data;
}
public function getUserPermissions(int $userId): void
{
// 从数据库加载用户权限
$this->permissions[$userId] = ['approve_workflow', 'review'];
}
}
使用数据库持久化状态
<?php
class DatabaseStateMachine extends AbstractStateMachine
{
private PDO $db;
private int $entityId;
private string $entityType;
public function __construct(PDO $db, string $entityType, int $entityId)
{
$this->db = $db;
$this->entityType = $entityType;
$this->entityId = $entityId;
$currentState = $this->loadCurrentState();
parent::__construct();
$this->currentState = $currentState;
}
protected function getTransitions(): array
{
return [
'new' => ['active', 'deleted'],
'active' => ['modified', 'archived', 'deleted'],
'modified' => ['active', 'archived'],
'archived' => ['deleted'],
'deleted' => []
];
}
protected function getInitialState(): string
{
return 'new';
}
private function loadCurrentState(): string
{
$stmt = $this->db->prepare(
"SELECT state FROM entity_states
WHERE entity_type = ? AND entity_id = ?
ORDER BY created_at DESC LIMIT 1"
);
$stmt->execute([$this->entityType, $this->entityId]);
$state = $stmt->fetchColumn();
return $state ?: 'new';
}
public function apply(string $state): void
{
parent::apply($state);
// 保存到数据库
$this->saveState($state);
}
private function saveState(string $state): void
{
$stmt = $this->db->prepare(
"INSERT INTO entity_states (entity_type, entity_id, state, created_at)
VALUES (?, ?, ?, NOW())"
);
$stmt->execute([$this->entityType, $this->entityId, $state]);
}
}
使用第三方库(推荐)
Symfony Workflow Component
<?php
use Symfony\Component\Workflow\Definition;
use Symfony\Component\Workflow\MarkingStore\MethodMarkingStore;
use Symfony\Component\Workflow\Transition;
use Symfony\Component\Workflow\Workflow;
use Symfony\Component\Workflow\Registry;
use Symfony\Component\EventDispatcher\EventDispatcher;
// 定义工作流
$transitions = [
new Transition('pay', 'pending', 'paid'),
new Transition('ship', 'paid', 'shipped'),
new Transition('complete', 'shipped', 'completed'),
new Transition('cancel', ['pending', 'paid'], 'cancelled'),
];
$places = ['pending', 'paid', 'shipped', 'completed', 'cancelled'];
$definition = new Definition($places, $transitions);
// 创建Workflow实例
$markingStore = new MethodMarkingStore(true, 'state');
$eventDispatcher = new EventDispatcher();
$workflow = new Workflow($definition, $markingStore, $eventDispatcher, 'order');
// 事件监听
$eventDispatcher->addListener('workflow.transition', function ($event) {
echo 'Transition from ' . $event->getTransition();
});
// 使用示例
class Order
{
private string $state;
public function getState(): string
{
return $this->state;
}
public function setState(string $state): void
{
$this->state = $state;
}
}
$order = new Order();
$order->setState('pending');
if ($workflow->can($order, 'pay')) {
$workflow->apply($order, 'pay');
echo "Order status: " . $order->getState(); // 输出: paid
}
最佳实践建议
1 状态机设计模式
<?php
interface StateInterface
{
public function proceed(): void;
public function cancel(): void;
public function getStatus(): string;
}
class PendingState implements StateInterface
{
private OrderState $context;
public function __construct(OrderState $context)
{
$this->context = $context;
}
public function proceed(): void
{
// 检查是否有足够库存等条件
if ($this->validatePayment()) {
$this->context->setState(new PaidState($this->context));
echo "Orders paid\n";
} else {
throw new \RuntimeException('Payment validation failed');
}
}
public function cancel(): void
{
$this->context->setState(new CancelledState($this->context));
echo "Order cancelled\n";
}
public function getStatus(): string
{
return 'pending';
}
private function validatePayment(): bool
{
// 验证逻辑
return true;
}
}
// 其他状态类类似...
class OrderState
{
private StateInterface $state;
public function __construct()
{
$this->state = new PendingState($this);
}
public function setState(StateInterface $state): void
{
$this->state = $state;
}
public function proceed(): void
{
$this->state->proceed();
}
public function cancel(): void
{
$this->state->cancel();
}
public function getStatus(): string
{
return $this->state->getStatus();
}
}
// 使用
$order = new OrderState();
$order->proceed(); // 输出: Orders paid
echo $order->getStatus(); // 输出: paid
2 注意事项
<?php
// 1. 状态转换的原子性
class TransactionalStateMachine extends AbstractStateMachine
{
private PDO $db;
public function applyWithTransaction(string $state): void
{
$this->db->beginTransaction();
try {
$this->apply($state);
// 其他业务逻辑
$this->db->commit();
// 触发事件在事务提交后
$eventName = sprintf('after_%s', $state);
$this->triggerEvent($eventName);
} catch (\Exception $e) {
$this->db->rollBack();
throw $e;
}
}
}
// 2. 状态机审计日志
class AuditTrailLogger
{
private PDO $db;
public function logTransition(
string $entityType,
int $entityId,
string $from,
string $to,
array $metadata = []
): void {
$stmt = $this->db->prepare("
INSERT INTO audit_log
(entity_type, entity_id, from_state, to_state, metadata, created_at)
VALUES (?, ?, ?, ?, ?, NOW())
");
$stmt->execute([
$entityType,
$entityId,
$from,
$to,
json_encode($metadata)
]);
}
}
// 3. 状态机的测试
class StateMachineTest extends PHPUnit\Framework\TestCase
{
public function testOrderFlow(): void
{
$order = new Order();
$machine = new OrderStateMachine($order);
$this->assertEquals('pending', $machine->getCurrentState());
$machine->pay();
$this->assertEquals('paid', $machine->getCurrentState());
// 测试非法转换
$this->expectException(\RuntimeException::class);
$machine->complete(); // 无法从 paid 直接到 completed
}
public function testInvalidTransition(): void
{
$machine = new OrderStateMachine(new Order());
$this->expectException(\RuntimeException::class);
$machine->apply('completed'); // 无效状态转换
}
}
性能优化
<?php
// 缓存状态转换配置
class OptimizedStateMachine extends AbstractStateMachine
{
private static array $cache = [];
public static function getTransitionsFor(string $entityType): array
{
if (!isset(self::$cache[$entityType])) {
// 从数据库或配置文件加载
self::$cache[$entityType] = [
'transitions' => include(__DIR__ . "/config/{$entityType}_transitions.php"),
'guards' => include(__DIR__ . "/config/{$entityType}_guards.php")
];
}
return self::$cache[$entityType];
}
protected function getTransitions(): array
{
return self::getTransitionsFor($this->entityType)['transitions'];
}
}
状态机模式在PHP中的应用要点:
- 清晰定义状态和转换规则
- 使用Guard/条件控制转换
- 事件驱动设计
- 事务性操作
- 完善的日志和审计
- 测试覆盖
- 考虑使用成熟库如Symfony Workflow
根据项目规模选择合适的实现方式:简单的可以用数组配置,复杂的建议使用专门的状态机库。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播