用 Kiro 构建可重复的 PHP 到 Java 迁移引擎

AWS ML Blog 2026-10-29T21:57:46.949235

团队把一个成熟的 PHP 应用迁移到 Java,能获得更强的类型安全、更丰富的类库支持,以及更可预测的扩展能力。但用 Laravel、Symfony 或 Doctrine 多年积累下来的 PHP 代码,往往把业务规则藏在一些不显眼的地方——从 Eloquent 的 trait 到 XML 映射文件都是如此。所以,即便照葫芦画瓢写出来的 Java 版本能干净地编译通过,运行时行为也可能和原来不一样。本文介绍如何借助 Kiro,把 PHP 到 Java 的迁移从一次「凭信念纵身一跃」变成可度量、可重复的流程。Kiro 是一款 AI 集成开发环境(IDE),它让 AI 代理与你的代码库协作,在你参与把关的前提下执行多步骤工程任务。这套做法的核心是一个可复用的引擎:一套共享方法论、一个机械化的发现扫描器,以及一个分八个阶段的工作流。这个引擎把原始 PHP 应用当作规格说明,在一致性校验工具(parity harness)验证通过之前,绝不宣布 Java 移植版本是正确的。

前置条件

开始之前,你需要:

你将在本文中学到什么

你会从一个开放的代码仓库入手,所以能亲手运行这个引擎,而不只是读读介绍。引擎掌握的所有知识都放在一小组 skill 文件里;有了这些文件,你可以用不止一种方式来运行同一套方法论。

运行引擎的两种方式:Kiro 与 AWS Transform

这里的一切都打包成 skill 文件:带版本号的 Markdown 能力包,编码了迁移方法论(php-to-java-migration)和发现扫描器工作流(php-model-discovery)。因为这些知识存在文件里,而不是绑定在某一个特定工具上,所以你可以用两种方式运行同一套方法论。

方法一:Kiro——交互式,开发者全程参与

Kiro 把一个 AI 智能体带进编辑器,一步步推进迁移。把仓库根目录作为 Kiro 工作区打开,当你让 Kiro 迁移一个 PHP 应用时,技能会自动激活。随后 Kiro 会沿着八阶段流程走,每个阶段都有明确的确认节点:你检查发现清单、确认规则手册,每个阶段都签字后才能进入下一阶段。本文所有示例用的都是这种方式。

方法二:AWS Transform——代理式,适合规模化迁移

AWS Transform 是 AWS 的代理式 AI 服务,面向大规模迁移和现代化改造,现在已与 Kiro 原生集成。通过这层集成,你可以把驱动 Kiro 交互式会话的同一套技能文件交给 AWS Transform,让“先发现,再翻译”、把一致性测试框架当裁判、以及“修闭环,不改代码”这些原则同样适用于自主运行。

两条路径各自的适用场景

控制与自主权:先用 Kiro 把代码走一遍——在单个应用上运行技能,读生成的 Java 代码,跑测试。想扩大规模时,再用 AWS Transform 以代理方式运行同一套方法论,在技能定义的检查点做人工审查。

规模与新颖性:Kiro 一次处理一个应用,适合首次遇到的新框架。AWS Transform 可以并行处理多个应用。

共享反馈闭环:两条路径读取同一套技能文件,因此在 Kiro 里做的每一次规则手册修正,都会让下一次 AWS Transform 运行受益,反过来也一样。

方案概览:一套大脑,多个项目

这套引擎围绕一个原则组织:一套大脑,多个项目。在本地克隆仓库,然后在 Kiro 里打开文件夹并选择仓库根目录(即包含 .kiro/ 的文件夹)。Kiro 会自动加载技能和引导配置,更完整的步骤见“快速上手”一节。

工作区把共享的方法论层与使用它的各个项目分开,如下图所示。最上层是全局 .kiro/ 层,每个项目都从中读取内容。下面是各个项目文件夹,每个都有自己的 PHP 源码、Java 输出和规格说明子文件夹。

图 1:工作区分为共享的全局方法层,以及每个项目各自的代码和 spec 文件夹

同样的共享 skill 文件可以用两种不同方式运行,如下图所示。同一套八阶段、优先验证一致性的流水线,既可以由 Kiro 驱动(交互式,一次处理一个应用),也可以由 AWS Transform 驱动(代理式,按组合规模运行),两者都把 PHP 源文件转换为一致性已验证的 Spring Boot Java。

图 2:同一组共享 skill 文件驱动两条执行路径——Kiro(交互式,一次一个应用)和 AWS Transform(代理式,组合规模)。两者运行同一套八阶段、优先验证一致性的流水线,把 PHP 源码转换为一致性已验证的 Spring Boot Java

.kiro/ 下的共享全局层包含两个 Skill:php-model-discovery(扫描器)和 php-to-java-migration(八阶段操作手册),外加 core-workflow.md 这个 Steering 文件。每个项目文件夹都有自己的 PHP 源码、Java 输出,以及 .kiro/specs/ 下的 spec 子文件夹。因此,方法只要改进一次,所有项目都能受益。

先发现,再翻译

最重要的一条规则要放在最前面:在扫描器跑完之前,不要读取、猜测或手工翻译任何模型或实体文件。

扫描器单遍工作、无依赖,如下图所示。它对源码 token 应用三种发现策略,输出一个 JSON 清单;遇到有歧义的内容,则送入 review-flag 队列,交给人工处理。

图 3:扫描器对源码 token 运行三种发现策略,输出一个 JSON 清单,并附带 review-flag 队列

扫描器就是 discover-models.php,一个单文件、无依赖的 PHP 命令行工具,不会执行目标代码。它只把源文本当作 token 来读取,因此无论依赖是否安装,都能对任意应用运行。每次扫描都会应用三种策略:

最终输出一个 JSON 清单。

models[] 数组记录每个字段、类型转换、关系和可见性规则,每个条目的 flags[] 数组也会出现。扫描器遇到歧义就标记出来,不擅自猜测。比如 $fillable 列表由运行时表达式生成,这种情况会变成一条用大白话描述的 flag,而这份 flag 列表就是人工审查队列。

以对齐为先的流水线

Phase 0 是准备阶段:运行扫描器并整理清单。接下来三个阶段集中投入人的专业判断。Phase 1 在写 Java 代码之前先搭好对齐测试框架,用请求/响应样本对分别回放 PHP 原版和 Java 移植版。这个框架必须在 PHP 正常工作时通过,并且在故意改坏代码时失败——漏掉人为注入故障的框架不可信。Phase 2 起草规则手册和缺口清单(RULEBOOK.md、GAP_INVENTORY.md),Phase 3 用代表性文件对它做压力测试,确认没问题再在整个应用里推行。

图 4:人的判断被前置到准备性的 Phase 0 和 Phase 1–3。Phase 4–8 基本是自动运转的循环,由对齐测试框架把关。

前四个阶段集中投入人的专业判断。Phase 0 运行扫描器并整理清单。Phase 1 在写 Java 代码之前先搭好对齐测试框架,用请求/响应样本对分别回放 PHP 原版和 Java 移植版。这个框架必须在 PHP 正常工作时通过,并且在故意改坏代码时失败——漏掉人为注入故障的框架不可信。Phase 2 起草规则手册和缺口清单(RULEBOOK.md、GAP_INVENTORY.md),Phase 3 用代表性文件对它做压力测试,确认没问题再在整个应用里推行。

阶段 名称 交付物
0 评估与摸底 模型清单(manifest)+ 清点表 + 切换方案
1 搭建「裁判」 能同时跑 PHP 和 Java 的对比测试台(parity harness)
2 规则手册 + 差距清单 RULEBOOK.md、GAP_INVENTORY.md
3 压力测试规则手册 加固后的规则手册,并用代表性文件验证过
4 搭建脚手架 能编译的 Spring Boot 工程
5 翻译数据模型 JPA 实体 + 数据库表结构基线
6 翻译输入输出层 控制器、安全配置、模板都能正常响应
7 转换业务逻辑 逻辑转换完成,测试全部通过
8 验证一致并切换 对比报告 + 切换检查清单

阶段 4~8 大多是自驱动的循环:阶段 4 搭出工程骨架,阶段 5 按清单翻译数据模型,阶段 6 翻译输入输出层(路由变成控制器,中间件变成过滤器,校验变成加了注解的数据传输对象),阶段 7 分批转换业务逻辑,阶段 8 用测试台验证两边行为一致,然后切换。

这个循环由两条原则支配。第一,PHP 代码就是规格说明:裁判认定一致,移植才算完成;否则每一处不一致都要记录成一次已批准的改动。第二,你修的是循环,不是代码——改规则手册然后重新生成,而不是手工打补丁。

实战演练:从 Eloquent 到 Spring Boot

laravel-eloquent-sample 项目的范围明确、可以直接跑起来:它来自一个开源 Laravel 应用,只做了只读的一个切片,把 Book、Chapter、Page、User 四个模型迁移到 Spring Boot 3.4.1、Java 21,用 Maven 构建,数据库是内存版 H2。

从 PHP 到 Spring Boot 的映射是机械的、可追溯的,如下图所示。左侧每个清单条目对应右侧一个 Java 构造,最终生成出这套应用切片的分层运行时架构。

图 5:左侧是清单驱动的映射关系,右侧是生成的应用切片的分层运行时架构

这些映射都是机械的,能追溯到清单上:PHP 命名空间变成 Java 包,Eloquent 模型变成 JPA 的 @Entity,hasMany 和 belongsTo 关系变成 @OneToMany 和 @ManyToOne,Eloquent 的查询作用域(query scope)变成 Spring Data 的 repository 方法。

这种严谨也体现在序列化上:html、markdown 和 text 字段都带上了 @JsonIgnore,因为清单文件记录它们位于 Page 的 $hidden 列表中,而 Book 的 description 字段则有意不加。规范文档坦承,37 个模型中只迁移了 4 个,更重要的是,这一部分从未构建一致性校验工具(parity harness),文档称之为“最大的单一缺口”。把不足之处记录下来,本身就是设计的一部分。

上手实践

完整的迁移引擎放在 PHP-to-Java 迁移示例仓库中。使用方法:

  1. 克隆仓库,把它的根目录作为 Kiro 工作区打开(打开文件夹,选择包含 .kiro/ 的那个目录)。除了扫描器需要 PHP 8.0+、运行需要 Java 21 和 Maven 之外,无需安装其他东西。
  2. 把 PHP 源码拉取到项目的 source-php/ 文件夹。README 中固定了用于一致性比对的上游提交哈希,任何人都能复现基线。
  3. 让 Kiro 迁移这个应用。php-to-java-migration 技能会自动激活,先运行扫描器,在 .kiro/specs/ 下生成一份新的规范文档,并带你走完各个审批关卡。
  4. 如果要走智能体(agentic)方式,把 AWS Transform 指向同一批技能文件,它的智能体就会在你的整个项目组合中执行同一套方法论。

这套方法论会自动识别 Laravel、Symfony、CodeIgniter 和原生 PHP,扩展方式是增量式的:支持新框架只需加一行检测规则,再加一份 references/-to-spring.md 指南。由于 Kiro 和 AWS Transform 读取的是同一批文件,改进一次就能同时升级两个引擎。

清理

如果你在本次演练中部署了示例 Spring Boot 应用:

发现扫描器只产出一个 JSON 清单文件。如果你不打算参考它,就把工作目录中扫描器的 JSON 清单删掉。

迁移引擎本身不会创建任何 AWS 资源,因此没有云资源需要释放。

本文介绍了如何用 Kiro 搭建一个可重复的 PHP 到 Java 迁移引擎,把大规模重写变成可度量、能持续积累的过程。核心原则有以下几条:

这些做法并不局限于 PHP 或 Java。只要旧系统是唯一的完整规格说明,其他迁移场景也适用同样的模式。

你可以克隆示例仓库 PHP-to-Java migration repository,在 Kiro 工作区中打开,探索支撑它的 Skills 和 Steering 能力;也可以把同一套技能文件带到 AWS Transform 中使用。想了解更多 AWS 上的语言迁移模式,请参阅 AWS Prescriptive Guidance 文档。

关于作者

Sarat Guttikonda

Sarat 是 Amazon Web Services(AWS)的首席解决方案架构师,与战略客户合作,设计和交付大规模云解决方案。他热衷于人工智能(AI)和机器学习(ML),帮助客户在保持业务敏捷的同时推动创新和转型。工作之外,Sarat 喜欢和儿子一起在 PS5 上玩合作游戏,也喜欢旅行和打羽毛球。

Phani Parcha

Phani 是 Amazon Web Services 的高级技术客户经理(战略客户),拥有 22 年以上构建和扩展企业平台的经验。他负责推动大型企业工作负载的架构卓越性、系统可靠性和运营性能。Phani 专精于分布式系统、微服务架构和云原生平台,重点关注企业转型和生成式 AI 解决方案。

Pallavi Jha 是 Amazon Web Services 的技术顾问,借助 Kiro 和 AI 驱动的开发生命周期(AIDLC)帮助客户提升开发者效率。她与正在进行工程实践现代化的企业合作,专注于用 AI 辅助、规格驱动的方式更快交付更高质量的软件。工作之余,她喜欢创作音乐和徒步。

有了 Kiro,PHP 到 Java 的迁移不再是靠运气的一次性冒险,而是一个可度量、可重复的过程。本文介绍一套可复用的引擎:一个自动化的发现扫描器,外加一套分八个阶段、对等性优先(parity-first,即先保证 Java 版行为与 PHP 原版一致)的工作流。它把原有的 PHP 应用当作规范,再用对等性校验工具验证 Java 移植版。

查看原文