Перейти к содержимому

Phasis

Движок JavaScript, написанный на PHP: ES2024+; проходит все 50 506 тестов test262 (снимок от 2025-05-05), а также поддерживает URL, кодирование, structuredClone, fetch и Streams.

Терминал
composer require phasis/phasis

Последний выпуск v0.4.2 MIT PHP 8.2+, ext-bcmath, ext-curl, ext-mbstring

На практике

Один объект движка запускает JavaScript в процессе PHP и передаёт значения в обе стороны.

Запускайте JavaScript из PHP

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

Проходит все 50 506 тестов набора на соответствие ECMAScript по снимку от 2025-05-05: все категории, без пропусков.

Современный ECMAScript

Классы, async/await, генераторы, Symbol, BigInt, Proxy, Temporal, TypedArray и Intl с ext-intl. Полная поддержка ES2024+.

API веб-платформы

Встроены URL, TextEncoder и TextDecoder, atob и btoa, structuredClone, performance и DOMException.

fetch + потоки

Настоящие HTTP через JS с помощью ext-curl. Полная реализация Fetch API с AbortSignal, Blob, FormData и WHATWG Streams.

Тесты веб-платформы

Импортированные подтесты WPT для fetch, headers, blob, abort, streams и encoding проходят, кроме разрешённого списка случаев с brotli и SharedArrayBuffer.

Совместимость PHP ↔ JS

setGlobal() предоставляет замыкания PHP как функции JS, а call() запускает функции JS из PHP. Значения преобразуются на границе; массивы копируются.

Встраиваемый

Один класс Engine: eval, execFile, setGlobal, call. Подходит для любого приложения PHP или CLI.

Ограничение стека вызовов

Фиксированный стек вызовов на 4 096 кадров останавливает бесконечную рекурсию и выдаёт перехватываемую InternalError.

CLI

bin/phasis запускает файл или фрагмент кода с флагом -e и выводит AST с флагом --ast. В клоне репозитория команда bin/test262 запускает набор тестов на соответствие.

Эталон Node.js

Сценарии проверяются по Node.js (V8). WPT и набор тестов библиотеки запускаются в CI при отправке изменений, затрагивающих движок; полный прогон test262 запускается по запросу, последний раз — 2026-06-09.

Настоящие библиотеки

204 пакета npm, включая acorn, mustache.js, lodash и marked, протестированы: вывод побайтно совпадает с Node.

Почему Phasis

Без процесса Node.js

Phasis разбирает и выполняет JavaScript непосредственно в PHP без вызова Node через exec() и без FFI. Устанавливается как пакет Composer.

fetch под контролем хоста

По умолчанию fetch() использует ext-curl. setFetchTransport() позволяет заменить транспорт, например, на имитацию в тестах, а setFetchPolicy() может отклонить или изменить каждый запрос перед отправкой.

Таймеры по виртуальному времени

eval() обрабатывает очередь событий до возврата, а часы перескакивают к следующему ожидающему таймеру вместо ожидания. Хосты с длительным временем работы могут запускать цикл в реальном времени с помощью tickEventLoop().

Парсер и форматтер в комплекте

Парсер возвращает типизированное AST PHP, которое экспортируется в ESTree. Форматтер повторно выводит JavaScript, JSON и CSS с форматированием, совместимым с prettier.

Сравнение с

Другие способы запускать или обрабатывать JavaScript из приложения PHP.

Phasis в сравнении с другими инструментами
Node.js Подходит дляNode.js запускает JavaScript на движке V8 и разрешает пакеты из каталогов node_modules, поэтому зависимости npm загружаются по имени. Отличия от PhasisВызов Node из PHP добавляет вторую среду выполнения и границу подпроцесса. Phasis работает внутри PHP, но его загрузчик модулей не поддерживает node_modules и разрешение экспортов package.json, поэтому пакеты npm сначала нужно собрать, например, с помощью esbuild.
V8Js Подходит дляV8Js встраивает движок V8 из Google в PHP и запускает JavaScript в песочнице, для которой можно задать ограничения по времени и памяти. Отличия от PhasisV8Js — скомпилированное расширение, которому нужна библиотека libv8. Phasis — это обычный PHP из Composer; в документации указано, что на коде с ограничением по диспетчеризации он работает примерно в 100 раз медленнее V8.
Peast Подходит дляPeast разбирает JavaScript в AST формата ESTree на PHP 5.4 и новее, а также поддерживает обход дерева, запросы с селекторами и рендеринг. Отличия от PhasisPhasis требуется PHP 8.2. Его парсер возвращает типизированные объекты узлов только для чтения с экспортом в ESTree; этот же пакет также может выполнять код.
Prettier Подходит дляPrettier форматирует JavaScript, TypeScript, JSX, CSS, HTML, Markdown, YAML и многое другое; устанавливается из npm. Отличия от PhasisФорматтер Phasis поддерживает только JavaScript, JSON и CSS. Его параметры соответствуют 3.x prettier; он работает в PHP без Node.js.

Вопросы и ответы

Краткие ответы из документации Phasis.

Начните с руководства для начала работы, затем изучите справочник API, посвящённый перехватчикам fetch и циклу событий.