用AI构建的基于Rust的PHP引擎通过了PHP-src测试套件的17%,并能渲染WordPress

Hacker News Top 新闻

摘要

一位开发者利用AI用Rust编写了一个PHP引擎,尽管此前没有Rust或编译器经验,但该引擎通过了PHP官方测试套件的17%,并能渲染WordPress。

暂无内容
查看原文
查看缓存全文

缓存时间: 2026/07/05 00:43

# 我不懂 Rust。但我的 AI 正在用它重写 PHP。 - ekinertac 来源:https://ekinertac.com/blog/i-dont-know-rust-my-ai-is-rewriting-php-in-it/ 几天前的晚上,我看着终端打印出一个 26 KB 的 WordPress 首页——"Phargo Test Site"、区块库 CSS、「Hello world!」(从 SQLite 数据库中拉取的),以及底部一个干净的 `<html>`。完全不起眼的输出,只有一个细节:**提供这个页面的 PHP 引擎中,没有一行 PHP 的实际源代码。** 这是一个从头用 Rust 编写的解释器。 下面这部分我需要你认真体会:**我不懂 Rust。** 我从未写过词法分析器。如果不打开另一个标签页看维基百科,我无法向你解释什么是「树遍历求值器」。如果你在派对上把我逼到墙角,问我 PHP 的垃圾回收器如何工作,我会假装接电话。 这个引擎叫 **Phargo**(https://github.com/ekinertac/Phargo),而我的贡献,粗略来说,就是「瞄准」。AI 写代码。我把它指向一个目标,像中世纪国王审阅航海图那样——严肃地点头,零理解——然后打出现代软件开发中最有力的一句话:*"looks good, continue."* ## 实验:坦诚作为构建系统 现在每个人和他们的盆栽都有个 AI 构建的项目,而且每个都带有同一个无法证伪的声明:「它能工作!」根据谁的标准工作?写它的 AI 吗?第四次录制才成功的演示吗? 因此整个实验建立在一个想法上,这个想法源于观察 Bun 团队如何用真实世界的测试套件驱动他们的 JavaScript 运行时:**不要让 AI 批改自己的作业。** PHP 自带自己的测试套件——大约 **22,000 个 `.phpt` 文件**,由 PHP 内部团队在三十年间编写。我没有写这些测试。AI 也没有写。这些测试编码了这门语言的每一个诡异角落,从 `DateTime` 夏令时计算,到 `var_dump()` 对一个浮点数究竟打印什么。 这个套件就是神谕。记分板运行全部测试,通过率**自动生成到仓库中**(https://github.com/ekinertac/Phargo/blob/master/PROGRESS.md)每次运行后。这个数字无法被奉承、协商,也无法通过提示语让它心情好转。要么 `bug40261.phpt` 通过,要么不通过。 当前分数:**22,037 个测试中通过 3,844 个——上游 PHP 整个测试套件的 17.4%。** 在你对 17% 嗤笑之前:实际的天花板大约在 40-45%,因为剩下的测试测试的是 C 扩展(GD、curl、SOAP、intl、MySQL 驱动……),这些明确不在范围内。在真正的竞技场里,这个爬升是非常真实的——它从零开始。 我作为人类的循环几乎尴尬得单薄: - AI 在整个语料库上运行失败直方图,找到它实际能修复的最大失败测试集群 - 它实现这个功能 - 它运行约 22,000 个测试的记分板(大约 7 分钟的风扇噪音) - 如果数字上升了:提交,推送,重复 - 如果数字下降了:我可以说我的*另一句*台词,「嗯,这个回退了,再看一遍」 就这些。这就是我的工作。我已经达到了巅峰的委派,我甚至不感到抱歉。 ## 神谕不能被贿赂。但测试工具却当面骗了我。 早期,通过率以某种感觉不对的方式停滞了。整类测试——明显简单的测试——不断失败,差异看起来和期望输出*一模一样*。我盯着那些差异,就像一个人盯着找不同谜题中的两张相同照片,什么也没发现。差异是看不见的,因为字面上就是看不见:**回车符。** 测试语料库是在 Windows 上用 CRLF 行尾签出的,我们的记分板按字节比较输出。PHP 自己的测试运行器在比较之前会标准化行尾。我们的不会。 这意味着测试工具仅仅因为行尾问题,就默默地让语料库中*几乎所有多行测试*失败,而且已经持续了数周。 一行标准化代码。**数百个测试瞬间变绿。** 这个教训像纹身一样刻在了项目上:**测量你的度量工具。** 你的神谕只和连接你与它的管道一样诚实。我们现在按照 `run-tests.php` 的方式精确标准化,而且此后每次可疑的平台期都会触发同样的问题——是引擎错了,还是记分板在撒谎? ## PHP 的测试套件是一个埋着地雷的雷区,附带一个自述文件 关于运行别人 22,000 个文件的测试套件,有件事没人告诉你:**有些文件是炸弹。** 不是恶意的——是无意的。针对古老内存 bug 的回归测试,分配荒谬的结构;生成器测试,无限膨胀;只打算在 PHP 自己精心围栏的 CI 中运行的测试。 我发现这一点的方式和所有伟大发现一样:我的开发机**硬重启了**。不是「程序崩溃」。不是「终端卡住」。整台电脑黑屏重启,因为一个生成器测试让我们的引擎吞噬了家里每一字节的 RAM,就像一辆没有刹车的火箭动力购物车。 后果让引擎变得多疑,而老实说它带着多疑很合适: - **封顶的全局分配器**——引擎物理上不能分配超过 6 GiB,无论测试多狡猾 - 步骤限制,所以无限循环以错误终止,而不是变成空间加热器 - 对字符串大小、数组节点、输出长度、生成器扩展的限制 - 一个面包屑文件,记分板用当前测试名更新它,所以当有东西挂起时,我们知道要瞪哪个文件 这些没有一个是光彩的语言实现工作。但所有这些就是「研究项目」和「能在我冲咖啡时安全地独自咀嚼 22,000 个恶意文件的东西」之间的区别。 ## 那些悄悄撒谎的特性 我最喜欢的 bug 类型——而测试套件*无情地*发现它们——是那些存在、能解析、无错误运行,但**完全不做任何事情**的特性。波将金虚拟内置函数。 几个月来,测试套件暴露了以下这些: - `clone`——解析正常,求值为 `NULL`。引擎范围。每个测试中的每个 `DateTimeImmutable` 都已经默默地永远坏了,因为不可变的日期运算*由 clone 构成* - `unset($arr[$key])`——完全无操作。键只是……留在那里 - `trim($str, $charlist)`——自创世以来就忽略 charlist 参数,只去除空白 - `$$` 变量变量——不存在 - `static` 函数变量——不存在 - `spl_autoload_register()`——微笑地接受你的自动加载器,却从不调用它 - `catch (\Throwable)`——什么也不匹配,对于一个万能捕获来说,这是一个非常有趣的属性 这些每一个都能在演示中存活。每一个都能在某个(不会读 Rust 的)人的代码审查中存活。**但没有一个能逃过测试套件。** 整个实验的论点就在这一个列表里:我无法审计代码,所以 22,000 个测试替我审计代码,其彻底性是任何人类审查员在中饭后都无法持续的。 ## 然后它提供了一页 WordPress 北极星一直是 WordPress——它是 PHP 兼容性的终极 Boss,一个古老到包含自 2003 年以来每一个 PHP 习语的沉积层的代码库。让 `wp-load.php` 甚至*引导*起来,就烧掉了一连串阻碍,读起来就像语言律师的狂热梦境:`goto`(是的,WordPress 的 HTML 解析器用了 `goto`)、`str_replace` 的引用 `$count` 参数、`\\xNN` 转义在正则字符类中、`function_exists()` 对一半内置函数视而不见。 然后安装程序损坏了自己的数据库,因为 `preg_split` 在 `wpdb::prepare` 内部忽略了 `PREG_SPLIT_DELIM_CAPTURE` 标志——一个比我所能诊断的任何东西都低四层的 bug,由 AI 在我监督下发现并修复,而我就像透过毛玻璃看开胸手术一样自信。 然后有一天晚上:`wp_install()` 完成。管理员用户创建,选项表填充好,SQLite 中有三篇文章。首页渲染出来——真实主题、真实文章、真实永久链接。 完全披露,因为坦诚是整件事的核心: - ✅ 新安装运行正常,首页从数据库渲染 - ✅ `/wp-admin/` 也渲染了——实际仪表盘,没有任何问题,说实话这比首页更让我惊讶 - ⚠️ REST API 是未探索的领域 - ⚠️ 目前**比真实 PHP 慢大约 55 倍**(7.1 秒对 126 毫秒)——不过全新的字节码虚拟机在微基准测试中已能达到 PHP 8.5 的 1-3 倍,即将追赶那个数字 ## 这到底是怎么回事 我一开始是想看看 AI 能不能写一个语言引擎。令人惊讶的答案是,这从来就不是真正的问题。当然*它*能写一个词法分析器——它读过每一个曾经发表过的词法分析器。真正的问题始终是:**一个不能验证代码的人如何保持项目的诚实?** 而答案原来是老派、无聊、美丽的:别人写的测试、一个只有在现实移动时才移动的数字、以及每一次结果推送到公共仓库,不管是否让我们脸上有光。 我仍然不懂 Rust。引擎现在大约有 24,000 行。记分板一次上升几十个测试,开发日志收集战争故事,而在某处有一个版本,WordPress 在浏览器中运行在一个编译为 WASM 的 Rust 引擎上。 看数字爬升:github.com/ekinertac/Phargo(https://github.com/ekinertac/Phargo)。或者不看也行,只要知道在某个地方,一个不会写解析器的人正在发布一个解析器,就够了。 *哦,显然:这篇文章也是用 LLM 起草的,然后由我编辑,直到听起来像我。机器写,我瞄准。这就是全部重点。*

相似文章

我们的Rust到Zig重写进展如何

Lobsters Hottest

Roc编译器团队已将他们30万行Rust代码库重写为Zig,经过18个月实现了功能对等,生成了更小的WebAssembly二进制文件并提高了性能。

我对Bun的Rust重写的看法

Lobsters Hottest

分析了Bun从Zig到Rust的争议性重写(使用AI生成的代码),引发了对合并的6,755个AI编写的提交未经人工审查以及AI翻译代码在生产环境中的风险的担忧。