跳转到正文

Phasis

以 PHP 编写的 JavaScript 引擎:通过全部 50,506 test262 测试(2025-05-05 快照),支持 ES2024+,以及 URL、编码、structuredClone、fetch 和 Streams。

终端
composer require phasis/phasis

最新版本 v0.4.2 MIT PHP 8.2+, ext-bcmath, ext-curl, ext-mbstring

实践应用

一个引擎对象可在 PHP 进程中运行 JavaScript,并双向传递值。

从 PHP 运行 JavaScript

Phasis\Engine 在调用它的 PHP 进程中执行源代码字符串和文件。setGlobal() 会将 PHP 数组转换为 JavaScript 数组和对象,并将 PHP 闭包包装为函数。

console.log 的输出会缓存在引擎中,并通过 getConsoleOutput() 读取。第二个标签页中的格式化器完全不需要引擎。

引擎
use Phasis\Engine;

$engine = new Engine();

// Evaluate an expression
$engine->eval('1 + 2 * 3');                  // 7

// Run a file
$engine->execFile('/path/to/script.js');

// Bridge a PHP value into JS (arrays are copied)
$engine->setGlobal('config', ['debug' => true]);
$engine->eval('config.debug');               // true

// console.log is buffered, not printed
$engine->eval('console.log("hi")');
echo $engine->getConsoleOutput();            // hi

// Expose a PHP closure as a JS function
$engine->setGlobal('greet', fn(string $name) => "Hello, $name");
$engine->eval('greet("world")');             // "Hello, world"

纯 PHP

无需 exec()、FFI 或 Node。需要 PHP 8.2+,并启用 ext-curl、ext-bcmath 和 ext-mbstring;CI 使用 PHP 8.4 和 8.5 运行。

100% test262

在 ECMAScript 一致性套件的 2025-05-05 快照中,通过全部 50,506 测试,覆盖每个类别且没有跳过项。

现代 ECMAScript

支持类、async/await、生成器、Symbol、BigInt、Proxy、Temporal、TypedArray 和 Intl(需 ext-intl)。完整支持 ES2024+。

Web 平台 API

内置 URL、TextEncoder 和 TextDecoder、atob 和 btoa、structuredClone、performance 及 DOMException。

fetch + 数据流

通过 ext-curl 从 JS 发出真实的 HTTP 请求。完整支持 Fetch API,包括 AbortSignal、Blob、FormData 和 WHATWG Streams。

Web 平台测试

导入的 WPT fetch、headers、blob、abort、streams 和 encoding 子测试均通过,brotli 和 SharedArrayBuffer 案例的允许列表除外。

PHP ↔ JS 互操作

setGlobal() 将 PHP 闭包公开为 JS 函数,call() 则从 PHP 调用 JS 函数。值会在边界处转换;数组会被复制。

可嵌入

一个 Engine 类:eval、execFile、setGlobal、call。可嵌入任何 PHP 应用或 CLI。

调用栈上限

固定的 4,096 帧调用栈可通过可捕获的 InternalError 阻止失控递归。

CLI

bin/phasis 可运行文件或 -e 代码片段,并通过 --ast 打印 AST。在代码仓库检出目录中,bin/test262 可运行一致性测试套件。

Node.js 基准

场景会与 Node.js(V8)进行比对。触及引擎的推送会在 CI 中运行 WPT 和库测试套件;完整的 test262 测试可按需运行,上次运行于 2026-06-09。

真实库

204 个 npm 软件包(包括 acorn、mustache.js、lodash 和 marked)均经过测试,输出与 Node 逐字节相同。

为什么选择 Phasis

无需 Node.js 进程

Phasis 直接在 PHP 内部对 JavaScript 进行词法分析、解析和执行,无需通过 exec() 调用 Node,也不使用 FFI。它以 Composer 软件包的形式安装。

由宿主控制 fetch

fetch() 默认使用 ext-curl。setFetchTransport() 可替换传输方式,例如在测试中使用模拟对象;setFetchPolicy() 则可在请求发出前拒绝或重写每个请求。

虚拟时间上的计时器

eval() 会在返回前清空事件循环,并让时钟跳到下一个待处理的计时器,而不是休眠。长期运行的宿主可以通过 tickEventLoop() 按实时方式驱动循环。

内置解析器和格式化器

解析器会返回带类型的 PHP AST,并可导出为 ESTree。格式化器会以兼容 prettier 的布局重新输出 JavaScript、JSON 和 CSS。

对比

在 PHP 应用中运行或处理 JavaScript 的其他方式。

Phasis 与其他工具的对比
Node.js 擅长领域Node.js 在 V8 引擎上运行 JavaScript,并从 node_modules 文件夹解析软件包,因此 npm 依赖项可按名称加载。 与 Phasis 的区别从 PHP 调用 Node 会增加第二个运行时和子进程边界。Phasis 在 PHP 内运行,但它的模块加载器不支持 node_modules,也不支持解析 package.json 导出,因此必须先打包 npm 软件包,例如使用 esbuild。
V8Js 擅长领域V8Js 将 Google 的 V8 引擎嵌入 PHP,并在沙箱中运行 JavaScript,可通过时间限制和内存限制来约束沙箱。 与 Phasis 的区别V8Js 是需要 libv8 库的已编译扩展。Phasis 是来自 Composer 的纯 PHP,其文档称,在受调用分派限制的代码中,运行时约为 100,是 V8 的倍数。
Peast 擅长领域Peast 可在 PHP 5.4 及更高版本中将 JavaScript 解析为 ESTree AST,并支持树遍历、选择器查询和渲染。 与 Phasis 的区别Phasis 需要 PHP 8.2。它的解析器返回带类型的只读节点对象,并可导出为 ESTree;同一个软件包也可以执行代码。
Prettier 擅长领域Prettier 可格式化 JavaScript、TypeScript、JSX、CSS、HTML、Markdown、YAML 等,并可从 npm 安装。 与 Phasis 的区别Phasis 格式化器仅支持 JavaScript、JSON 和 CSS。其选项与 prettier 3.x 一致,并在 PHP 中运行,无需 Node.js。

问答

来自 Phasis 文档的简明解答。

先从入门指南开始,然后阅读 API 参考文档,了解 fetch 钩子和事件循环。