登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  文章 >  php教程

PHP enum映射数据库状态值的迁移清单

来源:17golang原创

时间:2026-09-20 12:10:19 461浏览 收藏

迁移 PHP enum 时,最稳妥的做法是让数据库保存稳定的 backed value,而不是保存 case 名或对象结构。先盘点旧状态,再用 string backed enum 表达新契约;可信的内部值可以用 from(),来自数据库历史记录、接口请求或消息队列的值则优先用 tryFrom(),把未知值送入明确的异常处理路径。

官方文档:https://www.php.net/manual/en/language.enumerations.backed.php

要点速览
  • 数据库值是长期协议,enum case 名可以改,value 不应随意改。
  • 旧数字编码先经过映射表,再进入 enum;不要让每个控制器各自转换。
  • 未知状态不能静默当成 pending,要记录、隔离并给出回滚或人工处理路径。

先把数据库状态值当成兼容契约

我在迁移订单状态时最先做的不是写 enum,而是把历史列里的实际值分组:例如 012 可能分别表示待支付、已支付、已取消,也可能混入空字符串、拼写错误或已经废弃的状态。数据库里的值决定了回填范围,PHP 里的 case 只是新的类型边界。

建议先形成一张小型契约表,并给每个旧值写出目标值和未知处理策略:

旧值目标 backed value迁移动作未知时
0pending映射后回填保留原值并告警
1paid映射后回填进入人工队列
2cancelled映射后回填拒绝业务写入

用 backed enum 固定写入值和转换边界

下面的 enum 选择字符串作为持久化协议。case 名适合代码阅读,value 才是数据库和 JSON 需要稳定保存的值。旧系统的数字编码不直接塞给 enum,而是在转换器中完成一次明确映射。

 'pending', '1' => 'paid', '2' => 'cancelled'];
        $value = $legacy[(string) $raw] ?? (is_string($raw) ? $raw : null);

        // 未知值返回 null,调用方必须记录并决定隔离或失败。
        return $value === null ? null : OrderStatus::tryFrom($value);
    }

    public static function toDatabase(OrderStatus $status): string
    {
        // 只把 backed value 写回数据库,不写 case 名。
        return $status->value;
    }
}

这里不把未知值自动归为待支付,因为那会改变业务含义。只有在输入已经通过白名单校验时,才适合使用 OrderStatus::from($value);它找不到匹配 case 会抛出 ValueError,适合让调用失败而不是继续保存脏状态。

兼容读写比一次性改列更容易回滚

迁移通常分成三段。第一段保留旧列读取,同时在应用层统一经过 OrderStatusCodec;第二段让新写入只产生字符串 backed value,旧数字值只作为读取兼容;第三段按批次回填,并统计无法映射的原始值。回填完成后再收紧列约束或移除兼容分支。

  • 读路径:数据库原值 → 映射表 → ?OrderStatus,空结果进入隔离记录。
  • 写路径:业务对象 → OrderStatus$status->value,禁止控制器直接拼接状态字符串。
  • 回滚点:保留原始列或迁移日志,确认未知值为零且新旧读路径结果一致后再删兼容代码。

如果项目使用 ORM,可以把转换器挂在实体 hydration、custom cast 或 repository 边界上,重点是让“原始值如何变成领域状态”只有一个事实来源。

收尾检查:未知值、序列化和数据库约束

PHP backed enum 序列化到 JSON 时使用它的标量值,因此接口响应也会自然得到 pendingpaid 这类协议值。仍要检查客户端是否依赖旧数字编码,必要时在 API 版本层做兼容,而不是偷偷改变响应含义。

  • 抽样核对旧值总数、映射后总数和未知值总数。
  • 为未知值保留原始字符串、主键、发现时间和处理状态。
  • 确认新增状态时同时更新 enum、数据库约束、接口文档和回填脚本。
  • 最后才移除旧编码映射;删除前保留一份可回放的迁移记录。

延伸问答

数据库应该保存 enum 的 name 还是 value?

保存 backed enum 的 value。它是明确的标量协议,case 名可以为了代码风格调整,数据库值则应保持兼容。

什么时候用 from 而不是 tryFrom?

输入已经通过白名单或内部类型约束时可用 from();数据库历史值、用户请求和队列消息不够可信,优先用 tryFrom() 并处理 null。

未知状态能否直接映射成 pending?

不建议。未知值可能代表已完成或已退款等新业务状态,静默降级会造成错误操作,应记录原值并隔离。

PHP enum映射数据库状态值的静态边界结构图:旧状态值经过转换器进入OrderStatus并输出API值
图1:PHP enum 状态转换边界说明图,展示持久化值、转换器、领域对象和接口值之间的静态关系,不是截图或运行证据。
PHP数据库状态迁移契约结构图:orders.status、旧编码映射、回填记录和未知值隔离队列的关系
图2:数据库状态迁移契约说明图,帮助核对回填记录和未知值隔离边界,不表示实际执行顺序。
声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>