AI用Rust重写PHP引擎:已能渲染WordPress,通过17%官方测试

一个由AI驱动的实验
近日,一位开发者在Hacker News上分享了一个颇具野心的实验项目:使用AI辅助,用Rust语言从零构建一个PHP执行引擎。目前这个引擎已能通过PHP官方测试套件(php-src tests)约17%的测试用例,并成功渲染出WordPress页面。
这个数字看起来不高,但考虑到PHP是一门拥有二十多年历史、语义极其复杂的动态语言,且项目代码主要由AI生成,17%的通过率实际上是一个值得深思的信号——它揭示了当下大语言模型在处理大型、复杂系统级工程任务时的真实能力边界。
为什么选择用Rust重写PHP引擎?
性能与内存安全的双重追求
PHP官方引擎(Zend Engine)由C语言编写,自1999年随PHP 4发布以来历经多次重大迭代。Zend Engine由Andi Gutmans和Zeev Suraski在1999年重写并命名(两人名字的组合即"Zend"),其中Zend Engine 3随PHP 7问世时带来了高达两倍的性能提升——这得益于对内部数据结构的全面重设计,包括更紧凑的zval(PHP变量的内部表示)结构和更高效的哈希表实现,使PHP整体内存占用也大幅降低。
Zend Engine的执行流水线是理解PHP引擎复杂度的基础。Zend Engine的执行过程分为四个阶段,构成一条完整的编译-执行流水线:词法分析阶段由zend_language_scanner.l(基于re2c工具生成)将PHP源代码切分为Token流;语法分析阶段由zend_language_parser.y(基于Bison生成)将Token流解析为抽象语法树(AST);编译阶段将AST转换为线性的opcode序列,每条opcode对应一个操作符(如ZEND_ADD、ZEND_ASSIGN、ZEND_CALL),包含操作数类型和操作数值;执行阶段由execute_ex函数驱动的解释器循环逐条分派执行opcode。理解这条流水线,对于评估AI生成的引擎代码是否在正确抽象层次上处理语言特性至关重要——许多AI生成的错误正是源于在错误的阶段处理了本应属于另一阶段的语义问题。
Zend Engine本质上是一个基于寄存器的虚拟机:与早期基于栈的设计相比,寄存器VM可以减少指令数量、降低内存访问频次;其将PHP源码经词法分析、语法分析后编译为中间字节码(opcode),再由虚拟机解释执行。在字节码层面,Zend Engine使用OPcache扩展将编译结果缓存在共享内存中,避免每次请求重复解析PHP文件,这也是现代PHP性能调优的标准配置之一。值得一提的是,PHP 8.0还引入了基于DynASM框架实现的JIT(Just-In-Time)编译器,可将热点字节码直接编译为本地机器码,代表了Zend Engine架构的最新演进方向。C语言实现赋予了其高性能,却也带来了长期的内存安全隐患——历史上PHP进程中的内存泄漏、悬空指针和Use-After-Free漏洞是安全社区的常见议题。
Rust则以其所有权(Ownership)、借用(Borrowing)和生命周期(Lifetime)系统为核心,在编译期静态分析内存的分配与释放,从根本上杜绝了此类漏洞,且无需垃圾回收器的运行时开销。这套系统由编译器的"借用检查器"(borrow checker)静态验证:每个值有且只有一个所有者;引用分为不可变借用和可变借用,且两者不能同时存在;编译器追踪引用的有效作用域,确保不出现悬空引用。
对于PHP引擎这类需要频繁管理动态类型值、引用计数对象的系统而言,Rust与PHP内存模型存在深层的技术契合。PHP的写时复制(Copy-on-Write,COW)语义在C实现中依赖zval结构体中的refcount字段手动管理,历史上因引用计数错误引发的Bug屡见不鲜。在Rust中,标准库的Rc<RefCell<T>>类型组合可以精确建模PHP的COW语义:Rc提供引用计数语义,RefCell提供内部可变性以支持写时复制时的修改操作,编译器会在运行时动态检查借用规则违例。对于需要跨线程共享的场景(如PHP的并发扩展),则可对应使用Arc<Mutex<T>>,从语言类型系统层面强制保证线程安全。
在Rust中建模PHP值类型是整个项目中最核心的工程决策之一。PHP的值包括null、bool、int(64位有符号整数)、float(IEEE 754双精度)、string(字节字符串,非UTF-8强制)、array(有序哈希表,键为int或string)、object(引用语义)、resource(文件句柄等不透明资源)以及PHP 8.1引入的enum。在Rust中,这通常表示为一个enum PhpValue { Null, Bool(bool), Int(i64), Float(f64), String(Rc<PhpString>), Array(Rc<RefCell<PhpArray>>), Object(Rc<RefCell<PhpObject>>), ... }。其中array和object必须使用Rc<RefCell<...>>包裹以支持PHP的引用传递语义,而string在只读场景下可省略RefCell以避免运行时借用检查开销。这种设计使得Rust的枚举大小受最大成员约束,通常需要通过Box进行堆分配来控制栈上大小。AI生成的代码在这一设计决策上容易产生性能与正确性的权衡失误,是人工审查的重点区域。
这种映射关系使Rust能在不牺牲执行效率的前提下,从根本上避免C实现中常见的引用计数错误。从理论上,Rust是替代C实现PHP引擎的理想选择。
用Rust重写PHP引擎的想法并非首次出现,此前社区已有类似尝试。但本项目的独特之处在于:大量实现工作交由AI完成,开发者更多扮演架构设计者和"验收者"的角色,通过持续的人机协作,逐步填补语言特性的实现空白。
渲染WordPress意味着什么?
能够渲染WordPress是一个极具说服力的里程碑。WordPress驱动着全球超过40%的网站,其代码库超过数十万行PHP,其架构以钩子系统(Hook System)为核心,分为动作钩子(Action)和过滤器钩子(Filter),通过add_action、apply_filters等函数实现插件与主题的松耦合扩展——这一机制大量依赖PHP的call_user_func、可变函数、闭包(Closure)和动态方法调用。
WordPress还深度依赖PHP的各种高级特性:魔术方法(__get、__call、__sleep、__wakeup等)用于对象缓存和序列化;spl_autoload_register实现类的自动加载;PCRE正则表达式驱动WP_Rewrite类进行URL路由,对preg_match、preg_replace_callback等函数的完整性依赖极深。WordPress还需要数据库交互和文件系统操作的配合,这意味着引擎不仅需要正确实现PHP语言核心,还需具备基本的扩展生态支撑。
WordPress之所以成为PHP引擎兼容性验证的"黄金标准",在于其代码库横跨了PHP历史上多个不同时代的编程风格与API用法。WordPress核心代码中仍保留了大量PHP 5.2时代的兼容性写法(如显式function.php风格的面向过程代码),同时又引入了PHP 7.4+的箭头函数(Arrow Function)、PHP 8.0的命名参数(Named Arguments)和联合类型(Union Types)。这意味着一个能渲染WordPress的引擎必须同时正确处理:旧式的mysql_*风格(通过wpdb抽象层)到PDO的过渡、__PHP_Incomplete_Class的反序列化兼容性处理、以及WordPress著名的WP_Error类对异常处理的替代模式(WordPress核心层在历史上刻意回避PHP异常机制)。此外,WordPress的wp-cron.php依赖PHP的输出缓冲(ob_start/ob_end_flush)机制,这是许多PHP引擎实现中容易遗漏的非核心但关键的功能点。能跑通WordPress首页渲染,意味着引擎至少在上述所有机制上实现了"足够好"的近似,即便存在边缘案例偏差。
从技术复杂度的视角来看,WordPress的成功渲染意味着这个引擎至少正确实现了:基于原型链的PHP对象继承模型(包括__construct/__destruct生命周期)、PHP数组作为有序哈希表的完整语义(array_map、usort等高阶函数)、字符串处理函数族(sprintf的格式化语义尤为复杂)、以及足够完整的文件I/O与数据库PDO接口抽象。每一项都是解释器实现中的重量级功能,能够同时支撑它们协调运作,确实远非"Hello World"级别的验证。
能跑通WordPress,意味着这个引擎已跨越了从"语言玩具"到"实用解释器"的关键门槛,实现了相当一部分PHP核心语义。
AI辅助大型系统开发的真实启示
17%背后的工程真相
要理解17%这个数字的分量,首先需要了解被测试对象的复杂程度。PHP官方测试框架使用.phpt格式文件,每个文件包含多个固定标记的段落:--TEST--(测试描述)、--FILE--(待执行的PHP代码)、--EXPECT--或--EXPECTF--(期望输出,后者支持格式化占位符)等,通过run-tests.php脚本执行并比对实际输出。目前整套测试套件包含超过16,000个测试用例,覆盖范围从基础类型语义、运算符行为、字符串函数库,到面向对象特性(接口、trait、匿名类)、生成器(Generator)、Fiber协程,乃至各种历史遗留的边缘行为。
这些测试用例的分布并不均匀。基础语言特性(变量、控制流、函数调用)的测试相对集中,而扩展函数库(仅ext/standard目录下的字符串、数学、数组函数就有数千个测试)和OOP特性(traits的冲突解决规则、接口的协变/逆变类型检查、匿名类的作用域捕获)的测试则覆盖了大量极端边界情况。业界通常将70%以上的通过率视为"具备基本生产可用性"的参考门槛,这使17%的成绩既值得肯定,也清晰标定了距离目标的差距。
其中最具挑战性的当属PHP弱类型系统的历史演变。在PHP 7及之前,0 == 'foo'为true(字符串被转换为数字0),100 == '1e2'为true;PHP 8.0对此进行了重大调整,将数字与非数字字符串的比较改为字符串比较,使0 == 'foo'变为false。更复杂的是,PHP的类型转换规则呈现出"类型杂耍"(type juggling)特性:同一个值在不同上下文中会呈现不同类型,例如字符串"1"在算术运算中是整数1,在布尔上下文中是true,在严格模式(declare(strict_types=1))中则保持字符串。
PHP的类型转换规则远比表面看起来复杂,构成了一张相互交织的语义网络,也是AI生成代码最密集的偏差来源。在比较语义层面,PHP 8之前的==运算符遵循"类型协变比较"规则:两个纯数字字符串(如"123"和"456")按数字比较;数字与字符串比较时字符串转为数字;两个字符串均为非数字时才按字符串比较。这产生了著名的传递性失效问题:"1" == 1(字符串转数字)且1 == "1abc"("1abc"转为1)但"1" != "1abc"(两个字符串均非纯数字,按字符串比较),违反了等价关系的传递律。在布尔转换层面,PHP的"假值"(falsy)集合包含:false、null、整数0、浮点数0.0和-0.0、空字符串""、字符串"0"(注意:"0.0"是true!)、空数组[]。这一规则中"0"为假但"0.0"为真的不对称性是极易被AI实现遗漏的边缘情况。在整数溢出语义层面,PHP中整数溢出不会产生未定义行为(区别于C),而是自动转换为浮点数,这意味着实现者必须在每次整数运算后检测溢出并进行类型提升。这类隐含在PHP规范中的"自然语言描述"往往是AI生成代码产生偏差的高密度区域。
这类跨版本语义变更对实现者构成极大挑战,每一处类型转换细节都是AI容易产生偏差的高风险区域。
17%的测试通过率提醒我们,AI生成代码在攻克"长尾复杂度"时仍面临巨大挑战。当前大语言模型在系统编程领域呈现出明显的"高频知识强、长尾知识弱"特征:对于有大量训练数据支撑的主流API用法和常见算法实现,AI可以高质量生成代码;但对于规范文档中一句话带过的边缘语义、特定版本的兼容性行为,AI往往倾向于"合理推断"而非严格遵循规范,产生看似合理却行为错误的实现。这与解释器开发对规范符合性的极端严苛要求形成了本质矛盾。
换言之,AI能快速搭建出一个"看起来能用"的引擎骨架,甚至跑通主流应用,但要达到生产级的完备性与正确性,剩下的83%可能需要付出远超前17%的努力。这完全符合软件工程中经典的"最后一公里"定律。
人机协作的新开发范式
这个项目事实上践行了一种新兴的"测试驱动AI开发"范式(TDD-AI)。测试驱动开发(TDD)由Kent Beck在极限编程(XP)方法论中系统化提出,其核心循环为"红-绿-重构":先写一个失败的测试(红),再写最小量的代码使测试通过(绿),最后在保持测试通过的前提下重构代码。
将这一范式与AI代码生成结合,产生了一种极具潜力的协作模式。其核心机制在于:测试套件将模糊的自然语言需求("正确实现PHP的字符串比较语义")转化为精确的、机器可验证的输入-输出规约(具体的.phpt测试文件),从而大幅降低了AI代码生成的歧义空间。"写最小量代码"这一步骤由语言模型承担,而测试套件的通过率则提供了客观、自动化的反馈信号,替代了耗时的人工代码评审。更重要的是,测试通过率的可量化性(从X%提升到Y%)为AI提供了明确的优化目标,使"AI生成代码→自动运行测试套件→分析失败用例→定向修复→再次测试"的迭代循环得以持续自动运转,形成闭环反馈系统。
TDD-AI范式的成功依赖一个关键前提:测试套件本身的质量与覆盖率。在PHP的php-src测试套件这一场景中,这一前提相对成立——PHP官方测试套件由核心开发者维护,具有较高的规范符合性。然而,这一范式也存在几个典型的失效模式。"针对测试过拟合"问题:AI可能产生专门通过特定测试用例的实现,而非正确实现通用语义,即所谓的"测试套件作弊"(test suite gaming)。"幸存者偏差"问题:当前17%的通过率意味着AI已学会优先实现"易得分"的测试,而剩余83%中可能有相当比例是相互依赖的功能簇,一旦开始攻克就面临多个测试同时失败的局面,AI的局部优化策略在此可能失效。"测试意图理解"问题:AI分析失败测试用例时,可能错误解读测试意图,产生"修复了表象但未修复根因"的补丁,导致修复一个测试的同时破坏三个原本通过的测试(回归问题)。因此,在TDD-AI流水线中引入人工干预节点——尤其是在功能模块边界处进行架构级审查——仍然是保证整体正确性推进的必要机制。
GitHub Copilot、Cursor等工具已在日常工程实践中验证了这一方向,而本项目将其推向了更大规模的系统级工程场景。在开源编译器基础设施(如LLVM的测试套件)、数据库引擎(SQLite的庞大测试集)、网络协议实现(如HTTP服务器的合规性测试)等同样拥有高质量标准测试套件的领域,这种TDD-AI开发方式具有极高的复制价值,有望成为系统软件领域人机协作的重要范式。
理性看待:机遇与局限并存
值得肯定的探索价值
无论最终能否成为可用的PHP实现,这个项目本身就是对AI编程能力的一次极佳压力测试。它将AI置于知识密集、细节繁琐、容错率极低的真实场景中,为开发者社区提供了宝贵的实践参考数据。
需要清醒认识的现实差距
从17%到接近100%的兼容性,从"能渲染WordPress"到"能安全运行任意生产环境代码",中间横亘着巨大鸿沟。语言实现的正确性、性能调优、生态兼容性、安全审计——每一项都是AI目前难以独立完成的硬骨头,仍需人类专家主导把关。
尤其是安全层面,PHP历史上大量CVE漏洞正是源于引擎层的边缘行为处理不当——类型转换的细微差异可能导致身份验证绕过(如历史上PHP的==比较中'0e123' == '0e456'均为true的魔法哈希漏洞)、整数溢出的边界条件可能引发缓冲区越界、序列化对象的类型混淆(PHP对象注入攻击,POP链利用)可能导致远程代码执行。
对于一个试图生产化的PHP引擎实现,安全验证不能依赖功能测试套件,需要专门的安全测试基础设施。在业界实践中,针对语言运行时的安全验证通常采用三层方法:第一层是差分模糊测试(Differential Fuzzing),即同时运行目标引擎和官方Zend Engine,以相同的随机生成PHP代码片段作为输入,比对两个引擎的输出差异——任何输出不一致都是潜在的安全语义偏差。这一方法由Google的OSS-Fuzz项目在V8、CPython等项目上大规模验证。第二层是专项变异测试,针对已知的PHP CVE漏洞模式(如类型混淆、整数溢出、unserialize链)构建专项测试用例,验证新实现是否复现或规避了已知漏洞类别。第三层是静态污点分析(Taint Analysis),追踪用户输入($_GET、$_POST等)到危险函数(eval、system、include)的数据流路径,验证新实现中污点传播语义是否与Zend Engine一致。Rust语言的类型安全特性可以从根本上消除C语言引擎中的一类内存安全漏洞,但PHP语义层面的安全问题(如类型杂耍引发的逻辑漏洞)仍需上述方法体系独立验证,Rust的安全保证对此无能为力。
这些细节的正确性无法依靠"大致合理"的AI推断来保障,需要具备深厚PHP内部机制知识的专家进行逐一审计,并辅以模糊测试(fuzzing)等自动化安全验证手段。
结语
用AI构建Rust版PHP引擎,是一个充满理想主义色彩的技术实验。17%的通过率既是成就,也是一面镜子,照出了AI辅助编程的真实水平:它能极大加速原型开发和骨架搭建,在测试驱动的反馈循环中持续迭代推进,却仍需人类专家在关键决策、边缘情况和质量把控上主导全局。
对于关注AI编程未来的开发者而言,这类项目的持续进展远比任何理论讨论都更具参考价值。不妨持续关注,看看在人机协作模式下,这个数字最终能爬升到多高。
相关推荐

Agent智能体开发入门:从概念到实战的完整指南
深入解析AI Agent智能体的核心架构与开发实战,涵盖自动化营销、智能客服、投资分析三大落地场景,以及单智能体与多智能体协作机制,帮助初学者快速掌握Agent开发思维与实践路径。

Codex五分钟建站真相揭秘:不是AI做网站,是AI帮你抄网站
揭秘短视频平台上火爆的Codex五分钟建站内容真相:博主们并非用AI原创网站,而是复制共享提示词或直接扒别人网站。了解AI编程工具的真实能力边界,别被焦虑营销带节奏。

提示词工程入门指南:从单次指令到系统化方法论
提示词工程零基础入门教程,详解提示词的四大作用、提示词与提示词工程的核心区别、六步系统化流程,以及必须了解的技术与落地局限性,帮你真正发挥AI的全部潜力。