各位 PHP 摸鱼大师、代码考古学家们,大家好!
欢迎来到今天的《PHP 专家级开发实战:论如何利用 Cursor/Trae 的 AI 能力辅助重构复杂的 PHP 遗留业务逻辑》讲座。
咱们今天不聊虚的。在座的各位,只要在 PHP 生态里混过三年以上的,肯定都经历过那个深夜,当你打开项目里的 OrderController.php,看到下面那行注释——
// TODO: 这段代码是两年前留下的,千万别动,动了会死人,修了会秃头。
然后下面跟着整整 600 行的 if-else 嵌套,还有一堆全局变量和硬编码的数据库连接。你的第一反应是什么?大概率是打开浏览器,搜索“PHP 程序员猝死新闻”,然后默默地把电脑合上。
但是!今天我们要换个玩法。我们要用 Cursor 和 Trae 这两位“AI 编程外挂”,把这坨祖传代码像剥洋葱一样剥开,甚至给它整容换脸。
别以为我是来教你用什么高级设计模式的,那太枯燥了。今天我们要讲的是实战,是如何让 AI 帮你在这个满是 Bug 的泥潭里,找到那条通往清爽代码的小路。
准备好了吗?把你的咖啡倒满,咱们开整。
第一部分:兵马未动,粮草先行——搭建你的 AI 剑阵
在动手之前,你得先有武器。Cursor 和 Trae 虽然长得像,但他们的战斗风格截然不同。
Cursor,它更像是一个精通 PHP 的“超级编辑器”。它不仅能写代码,还能读文件。它最大的特点是支持“Composer 模式”(虽然国内有点折腾,但值得尝试),最重要的是,它支持本地模型。这意味着你的敏感业务逻辑,连代码都出不了你的硬盘,这给了我们最大的安全感。
Trae 呢,它是字节跳动出品的“全能型选手”。它的核心杀手锏是“Agent”能力。简单来说,Trae 不只是一个改错字的打字机,它是一个能规划任务的“项目经理”。
我的建议是: 左手 Cursor(处理日常切片式重构),右手 Trae(处理系统级代码迁移和架构清洗)。
第二部分:当上帝类遇上 AI —— Cursor 的微观手术刀
咱们先来面对最常见的问题:上帝类。就是那个 User.php,它既管注册,又管登录,还管密码重置,甚至还要处理发短信验证码。这哪是类啊,这简直是托儿所。
假设我们有这么一段令人窒息的代码:
// app/Services/OrderService.php (拿你的生命开玩笑)
class OrderService {
public function processOrder($orderId, $paymentMethod, $discountCode = null) {
// 1. 查订单
$order = $this->db->query("SELECT * FROM orders WHERE id = ?", [$orderId]);
// 2. 查用户
$user = $this->db->query("SELECT * FROM users WHERE id = ?", [$order['user_id']]);
// 3. 查优惠券
$coupon = $discountCode ? $this->db->query("SELECT * FROM coupons WHERE code = ?", [$discountCode]) : null;
// 4. 各种 if 判断
if ($paymentMethod == 'alipay') {
// 支付宝逻辑,15行
} elseif ($paymentMethod == 'wechat') {
// 微信逻辑,18行
} elseif ($paymentMethod == 'credit_card') {
// 信用卡逻辑,20行
} else {
throw new Exception("支付方式不支持,你是来砸场子的吗?");
}
// 5. 扣款
// ...
// 6. 发邮件通知
// ...
}
}
现在,Cursor 已经在你心里装好了。怎么让它干活?
第一步:给它“看”。
在 Cursor 中,直接选中这段代码,按 Ctrl+K(Mac 是 Cmd+K)。你会看到一个输入框。在这里,你不用写长篇大论,AI 已经读到了你选中的内容。
第二步:下达指令。
输入:
“Please refactor this method to extract the payment processing logic into a separate class and handle the coupon calculation in a dedicated service.”
注意,指令要具体。不要说“优化这个代码”,要说“把支付逻辑提取出去”。
第三步:见证奇迹。
Cursor 会生成一个新文件 app/Payment/AlipayService.php 和 app/Services/CouponService.php,然后把原方法改成调用这些新服务。
效果大概是这样的:
// app/Services/OrderService.php (经过 AI 之手,顿觉清新)
class OrderService {
public function processOrder($orderId, $paymentMethod, $discountCode = null) {
$order = $this->db->query("SELECT * FROM orders WHERE id = ?", [$orderId]);
$user = $this->db->query("SELECT * FROM users WHERE id = ?", [$order['user_id']]);
$couponService = new CouponService();
$finalPrice = $couponService->calculate($order['total'], $discountCode);
$paymentService = $this->getPaymentService($paymentMethod);
$paymentService->pay($order, $finalPrice);
$this->sendNotification($user, 'order_placed');
}
}
看!是不是清爽多了?原本 50 行的混乱逻辑,变成了 5 行清晰的调用。AI 帮你把那个巨大的 switch 语句变成了依赖注入的 getPaymentService。
这就是 Cursor 的厉害之处:它知道 PHP 生态里有哪些现成的工具(比如 Laravel 的 Service Container),它知道该用什么命名规范。
第三部分:Trae 的 Agent 模式 —— 大规模战争中的总指挥
有时候,你想做的是更宏大的工程,比如“把所有使用 mysql_query 的地方全部替换成 PDO”。或者“把所有硬编码的时间格式统一改成 Carbon”。
这种情况下,Cursor 需要你一个文件一个文件地选中,太累了。这时候,Trae 的 Agent 模式 就该上场了。
实战演练:
- 打开 Trae。
- 在聊天窗口输入:
“我有一个历史遗留项目,里面有大量的代码直接使用了
mysql_query,而且没有预处理。请帮我分析一下项目结构,找出所有使用这些函数的文件,并编写一个脚本来批量替换它们为 PDO 的 prepare 和 execute 方法。”
Trae 的 Agent 会启动。你会看到它在控制台疯狂滚动:
Analyzing project...
Found 42 files using mysql_query.
Checking dependencies...
几秒钟后,它会给你一个方案。它能看懂你的项目结构,甚至能帮你生成一个 PHP 脚本,让你运行它来批量替换文件内容。
这不仅仅是改代码,Trae 在帮你理解上下文。它能分辨出哪些 mysql_query 是用来获取配置的(可能不能动),哪些是用来查询数据库的(必须动)。
Trae 的优势在于它的“规划能力”。它不会像 Cursor 那样直接给你改完,它会告诉你:“为了安全起见,我建议你先备份数据库,然后我先改一个文件给你看,你确认没问题了,我再批量执行。”
第四部分:重构的艺术 —— 当“魔法字符串”遇见“枚举”
PHP 代码里最恶心的东西是什么?不是 eval(),而是魔法字符串。
你看看这个:
if ($status == 'pending') { ... } 或者 if ($type == 'admin') { ... }
今天天气是阴的,明天 status 就可能变成 pending_review,后天变成 waiting_user_action。你的代码里全是这种字符串飘来飘去,改一个地方,忘了另一个地方,Bug 就来了。
怎么用 AI 破局?
假设你决定引入 BackedEnum (PHP 8.1+) 来规范状态。
操作流程:
- 在 Trae 或 Cursor 中,让 AI 帮你生成这个枚举类。
- Cursor 接受指令:
Create a PHP Enum for OrderStatus with values: PENDING, PAID, CANCELLED, REFUNDED.
AI 生成了:
enum OrderStatus: string {
case PENDING = 'pending';
case PAID = 'paid';
case CANCELLED = 'cancelled';
case REFUNDED = 'refunded';
}
接下来是重头戏:全局替换。
在 Cursor 中,你可以使用 Composer 模式 或者直接在代码里搜索替换。
但更高级的用法是:“让 AI 帮我写一个迁移脚本”。
你可以问 Trae:
“帮我写一个 Laravel 迁移脚本,把数据库里所有的 order_status 字段从字符串类型更新为对应的枚举值,并处理旧数据(比如旧的 ‘old_status’ 映射到新的 OrderStatus)。
Trae 会生成一段迁移代码,利用 Model Casting 和 casts 方法。这样,你的数据库还是字符串,但代码层面你已经用了强类型枚举。这是非常平滑的重构。
第五部分:面对“祖传 PHP 5.6”时代的代码
如果你不幸接手了一个还在运行 PHP 5.6 项目的公司,那你真的需要祈祷了。那个世界里充满了:
global $config;require_once 'db.php';(到处都是)class MyClass extends DBConnection { ... }
这时候,AI 的作用不仅仅是写新代码,而是教你如何写新代码。
假设你看到一段代码是这样的:
function getOrder($id) {
global $conn;
$res = $conn->query("SELECT * FROM orders WHERE id = $id");
return $res->fetch_assoc();
}
你想重构它,但不敢动,怕崩。
利用 Cursor 的“对话式补全”和“提示词工程”:
你可以让 AI 陪你“逐行”重构。
第一步:先让它写一个接口。
Cursor 提示:
“Would you like me to create an interface
OrderRepositoryInterfaceto replace this function?”
你点“Accept”。
第二步:让它写一个实现类。
Prompt: “Now create a MySQLOrderRepository that implements this interface using PDO.”
第三步:让 Cursor 帮你替换调用。
你告诉 Cursor: “Find all places in the codebase that call getOrder and replace them with $orderRepo->getById($id).”
Cursor 会列出所有调用的文件,让你确认。它甚至会警告你:“这个文件还有 10 处调用,确认全部替换吗?”
这种可解释性和可控性,是传统 IDE 做不到的。AI 就像一个从没来过这个世界的实习生,他虽然不懂业务,但他能帮你把东西搬得整整齐齐。
第六部分:Trae 的“Chat with Codebase” —— 代码库级别的医生
Cursor 有 Composer,Trae 有 “Chat with Codebase”。这是 Trae 的独门绝技。
想象一下,你想重构整个项目的日志系统。原来的日志是直接写在文件里的,你想改成写入 Elasticsearch。
你不需要去读每一个文件。你只需要在 Trae 里问:
“请分析整个项目,找出所有直接调用
file_put_contents用于记录日志的地方,并告诉我它们大概有多少个文件,以及它们主要记录了什么类型的信息。”
Trae 会扫描你的整个项目(当然要你授权),然后给你一份报告:
app/Controller/AdminController.php– 记录了登录失败。app/Service/PaymentService.php– 记录了支付异常。app/Utils/Logger.php– 记录了系统级别的错误。
然后你可以说:
“把这些日志调用全部改成使用新的
ElasticLogger类。”
Trae 的 Agent 会直接去修改那些文件。它不会只改一个,它会逐个文件打开,读取,修改,保存。而且,Trae 比较擅长处理这种多文件关联的逻辑,因为它是在“代理”你的鼠标和键盘。
第七部分:避坑指南 —— AI 也会“发疯”
讲了这么多好处,咱们也得聊聊 AI 的阴暗面。AI 虽然强,但它也是 AI。在处理 PHP 这种弱类型、动态语言的遗留代码时,它经常会出现幻觉。
坑 1:变量名幻觉
你告诉 AI:“把 $u 改成 $userId”。
AI 可能会改了一半,剩下的一半它懒得改了,或者它根本没看懂上下文,导致 $u 还是 $u,而 $userId 却多出来了一堆垃圾变量。
坑 2:语法错误
有时候为了追求“优雅”,AI 会引入一些你项目中没有的依赖,或者引入 PHP 8.2 才有的特性,导致你的 PHP 7.4 环境直接报 Fatal Error。
坑 3:破坏业务逻辑
这是最可怕的。比如一个复杂的计算公式,AI 为了简化,把精度丢失了,或者把正负号搞反了。
如何防坑?
- 保留 Git 历史记录:重构前一定要
git commit。AI 改坏了?git checkout。这是你的救命稻草。 - 使用 Cursor 的 Composer 模式:如果你用 Cursor,一定要开启 Composer 模式。它会让你逐个确认每一个修改。这虽然慢,但是稳。
- 不要相信 AI 的第一行代码:不要觉得它写的全是完美的。对于重构,尤其是遗留代码重构,Code Review 是绝对必要的。把它当作一个初级实习生,你得教他,也得检查他的作业。
- 分块重构:不要让 AI 一次性重构整个
vendor目录,也不要让它重构整个src目录。聚焦在一个具体的类或方法上。
第八部分:实战案例复盘 —— 从 2000 行到 200 行
让我们模拟一个真实的场景。
你接手了一个电商系统的退款模块。RefundController.php 有 2000 行代码。里面的 process() 方法有 500 行。它包含:
- 查询订单
- 查询物流信息
- 计算退款金额(包含优惠券、运费、税费)
- 检查退款原因是否合规
- 调用第三方支付接口
- 更新库存
- 发送通知
- 写入财务报表
- 处理异步回调
这是一个典型的“面条式代码”。
实战步骤:
-
第一步:分离业务逻辑(Trae)
- Prompt: “Help me extract the order validation logic from the
processmethod into a separate classOrderValidatorService.” - Trae 创建了类,移出了代码。
- Prompt: “Help me extract the order validation logic from the
-
第二步:拆分计算逻辑(Cursor)
- 选中计算退款金额的那段乱七八糟的数学公式。
- Prompt: “Extract this calculation into a
RefundCalculatorservice. Keep the business rules, but make it pure logic (no database calls).” - Cursor 创建了纯函数逻辑。
-
第三步:处理第三方集成(Cursor + Trae)
- 把调用支付接口的代码单独拿出来。
- Prompt: “Create an interface
PaymentGatewayand implementWechatPaymentandAlipayPaymentbased on the existing logic.” - Cursor 完成了接口定义和实现。
-
第四步:清理 Controller(Trae)
-
现在
process方法只剩下:public function process($data) { $validator = new OrderValidatorService(); if (!$validator->validate($data)) return; $calculator = new RefundCalculator(); $amount = $calculator->calculate($data); $gateway = PaymentFactory::create($data['channel']); $gateway->refund($data['transaction_id'], $amount); $this->notifyService->send($data); } -
Prompt: “Refactor the controller to use Dependency Injection for all these services. Clean up the comments and ensure the code is readable.”
-
最终结果:Controller 从 500 行变成了 50 行。
第九部分:未来展望 —— 我们会成为 AI 的奴隶吗?
有人问:“学会了这些 AI 工具,我是不是会被淘汰?”
我的回答是:你不会因为会用 AI 而被淘汰,但会用 AI 的 PHP 程序员会淘汰那些只会盲目写代码的 PHP 程序员。
Cursor 和 Trae 是你的副驾驶,而不是你的替身。它们不懂什么是“为了赶工期偷懒少写两行注释”,也不懂什么是“老板那个奇怪的需求背后的潜台词”。
重构遗留代码,本质上是一种解构和重组的艺术。
Cursor 和 Trae 最擅长解构。它们能一眼看穿那些复杂的循环和嵌套。
但是,重组——即理解为什么这里要用 PDO 而不是 mysqli,为什么这里需要加事务——这还得靠你。
你要用你的 PHP 知识库去校对 AI 的每一个改动。如果 AI 修改后的代码能让你拍大腿说:“哇,这个重构太绝了!”,那才是真正的成功。
结语:去修复那个 TODO 吧
好了,讲座时间到了。我假设你们现在的心情是这样的:看着屏幕上那行 // TODO: 这段代码是两年前留下的...,突然觉得它也没那么面目可憎了。
打开 Cursor,选中那段代码,按一下 Ctrl+K,输入你的指令。
哪怕只重构了一个函数,哪怕只消除了两个魔法字符串,那也是胜利。
记住,代码是给人看的,顺便给机器运行。那些混乱的遗留代码,就是历史留给我们的宝藏,等着我们去挖掘,去修复,去让它们重焕新生。
祝大家在 PHP 的世界里重构愉快,Bug 少少,头发多多!
下课!